iOS  Runtime 知识详解: http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/

一般可以运行Runtime进行以下操作:

  1.在程序运行时,动态的添加一个类

  2.在程序运行时,动态的修改一个类的属性,方法

  3.遍历一个类的所有属性

举个🌰:

1.交换系统的方法和自定义的方法的实现.

如,使用NSString 的stringWithFormat可以得到一个字符串,如果想为这个字符串默认加上一段字符就可以使用runtime中的method_exchangeImplementations的实现.

如:写一个NSString的category.然后引入runtime,可以在load方法里面通过class_getClassMethod得到方法,然后通过method_exchangeImplementations交换即可.

NSString的category的代码如下:

NSString+str.m

//
//  NSString+str.m
//  Runtime
//
//  Created by Shaoting Zhou on 2017/10/19.
//  Copyright © 2017年 Shaoting Zhou. All rights reserved.
//

#import "NSString+str.h"
#import <objc/message.h>

@implementation NSString (str)
//当文件被加载进来时调用
+(void)load{
    Method stringWithFormat = class_getClassMethod([NSString class], @selector(stringWithFormat:));
    Method ST_stringWithFormat = class_getClassMethod([NSString class], @selector(ST_stringWithFormat:));
    //方法交换
    method_exchangeImplementations(stringWithFormat, ST_stringWithFormat);
}

+(instancetype)ST_stringWithFormat:(NSString *)str{
    NSString * appendStr = [str stringByAppendingString:@",带上我"];
    return appendStr;
}
@end

使用还是按照原来的stringWithFormat即可:

其中,苹果在iOS5.0之后,不建议使用底层代码,如果想要使用,需要修改配置,如

修改Build Setting中Enable strict ..........为NO即可.

2.动态添加方法 

写一个继承于NSObject的类Person,然后调用一个它实现的方法.这个时候苹果为我们提供了一个方法:+(BOOL)resolveInstanceMethod:(SEL)sel可以在里面做一下处理.

这里介绍一下动态添加方法:class_addMethod

Person.m

//
//  Person.m
//  Runtime
//
//  Created by Shaoting Zhou on 2017/10/19.
//  Copyright © 2017年 Shaoting Zhou. All rights reserved.
//

#import "Person.h"
#import <objc/message.h>
@implementation Person
void runMe(){
    NSLog(@"你没有实现这个方法");
}
//当发现类有实例方法没有实现时,会提供一次机会做处理
+(BOOL)resolveInstanceMethod:(SEL)sel{
//    NSLog(@"%@",NSStringFromSelector(sel));
    //动态添加方法
    if(sel == @selector(ppp)){
        /*
         class 类
         SEL 方法编号
         IMP 方法实现
         types 类型
         */
        class_addMethod([self class], sel, (IMP)runMe, "");
    }
    return [super resolveInstanceMethod:sel];
}


@end

3.获取属性

//动态的取属性
    unsigned int count = 0;
    Ivar * ivars = class_copyIvarList([Person class], &count);
    // 遍历成员变量列表,其中每个变量都是Ivar类型的结构体
    for (const Ivar *p = ivars; p < ivars + count; ++p)
    {
        Ivar const ivar = *p;
        // 获取变量名
        NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
        NSLog(@"%@",key);
    }

4.以后慢慢添加.

 

源码下载