iOS-Runtime

1.什么是runtime?

runtime:运行时机制,也是一种消息机制,是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。
在我们编写的OC语言中,程序运行时,也是通过runtime转化为C语言代码进行编译的,
例如:

    // 把Person *p = [[Person alloc]init]分解
    Person *p = [Person alloc];
    Person *p = objc_msgSend(objc_getClass("Person"), sel_registerName("alloc"));

    p = [p init];
    p = objc_msgSend(p, @selector(init));

2.runtime有什么作用?

runtime属于OC的底层操作,可以实现使用OC语法无法实现的方法和功能:

  • 获取一个类所有的方法,包含私有方法
// 获取类中的方法
- (void)getMethodList
{
    int a = 0;
    int b = 10;
    int c = 2;
    
    int arr[] = {a,b,c};
    int *p;
    p = arr;
    
    NSLog(@"%d %d",arr[1],p[1]);
    
    // 获取Person类中所有方法
    // 参数一:获取哪个类的方法列表
    // 参数二:方法列表总数
    unsigned int count = 0;
    
    // 调用完这个方法,count就有值,记录方法列表总数
    // 获取仅仅是当前类
    // 返回指向方法列表数组
    Method *methodList = class_copyMethodList([Person class], &count);
    
    // 2 0 1
    for (int i = 0; i < count; i++) {
        
        // 取出对应的方法
        Method method = methodList[i];
        
        // 获取方法名(方法编号)
        SEL methodSel =  method_getName(method);
        
        NSLog(@"%@",NSStringFromSelector(methodSel));
    }
}
  • 获取类所有的属性,包含私有属性
    其实打断点也可以获取一个类的所有属性

  • 方法交换


// 加载分类进内存的时候调用
+ (void)load
{
    NSLog(@"%s",__func__);
    // 交换imageNamed和yc_imageNamed实现
    
    // 获取imageNamed方法
    // Class:获取哪个类方法
    // SEL:获取方法方法编号
    Method imageNameMethod = class_getClassMethod(self, @selector(imageNamed:));
    
    // 获取yc_imageNamed方法
    Method yc_imageNameMethod = class_getClassMethod(self, @selector(yc_imageNamed:));
    
    // 交换方法实现
    method_exchangeImplementations(imageNameMethod, yc_imageNameMethod);

}

+ (instancetype)yc_imageNamed:(NSString *)name
{
    // 加载图片
    UIImage *image = [UIImage yc_imageNamed:name];
    
    if (image == nil) {
        NSLog(@"加载失败");
    }else{
        NSLog(@"加载成功");
    }
    
    return image;
}
  • 动态添加方法

#import "Person.h"

#import 

@implementation Person

// 没有返回值,没有参数
// void(*)()
// 完整方法实现
void eat(id self, SEL _cmd, NSString *str)
{
    NSLog(@"动态添加的吃方法 %@",str);
}

//  注意:任何一个方法都有两个隐式参数,self,_cmd
 
// 动态添加方法步骤
// 作用:处理未实现方法
// 什么时候调用:调用了一个未实现的方法就会调用这个方法
// 参数:未实现方法的方法编号
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    NSLog(@"%@",NSStringFromSelector(sel));
    
    // 动态添加eat
    if (sel == @selector(eat:)) {
        // 动态添加方法
        // Class:给哪个类添加方法
        // SEL:添加什么方法
        // IMP:方法实现,函数入口 -> 函数名
        // type:方法类型 v:void @:id :->SEL
        class_addMethod(self, sel, (IMP)eat, "v@:@");
        
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

@end
  • 动态添加属性
#import "NSObject+Property.h"

#import 

@implementation NSObject (Property)

- (void)setName:(NSString *)name
{
    // name保存到对应对象
    // 动态添加属性
    // object:给那个对象添加属性
    // key:属性名
    // value:把什么对象保存起来
    // policy:策略,用什么策略
    objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)name
{
    return objc_getAssociatedObject(self, @"name");
}

@end
  • 其他功能
    如字典转模型,利用runtime遍历模型对象的所有属性, 根据属性名从字典中取出对应的值, 设置到模型的属性上
    大家所熟知的MJExtension框架就大量使用了runtime

3.runtime使用

  • 头文件
// 使用runtime需要导入其头文件
#import 

// 或者导入其父类
#import 
  • 相关函数
// 以class_ 开头,这里就不一一列举了
// Ivar:成员变量            Method:成员方法
class_addIvar(<#__unsafe_unretained Class cls#>, <#const char *name#>, <#size_t size#>, <#uint8_t alignment#>, <#const char *types#>)
class_getName(<#__unsafe_unretained Class cls#>)
class_addMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>, <#IMP imp#>, <#const char *types#>)
class_getVersion(<#__unsafe_unretained Class cls#>)
class_addProperty(<#__unsafe_unretained Class cls#>, <#const char *name#>, <#const objc_property_attribute_t *attributes#>, <#unsigned int attributeCount#>)

4.应用实例

iOS-利用runtime修改TextField的占位文字颜色

iOS-Runtime_第1张图片

你可能感兴趣的:(iOS-Runtime)