1.Runtime系列-Runtime 知识小结

Runtime 知识小结

一. 什么是Runtime

  • 从运行时机来说

    RunTime简称运行时。就是系统在运行的时候的一些机制,其中最主要的是消息机制。对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 )。编译完成之后直接顺序执行,无任何二义性。OC的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(事实证明,在编 译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。

  • runtime也是oc底层的一个类。

runtime 的消息机制

消息转发机制和消息传递机制两种

消息转发机制

  • 动态方法解析->备用接收者->完整转发 三步骤

1.动态方法解析

对象在接收到未知的消息时,首先会调用所属类的类方法+resolveInstanceMethod:(实例方法)或 者+resolveClassMethod:(类方法)。在这个方法中,我们有机会为该未知消息新增一个”处理方法”“。不过使用该方法的前提是我们已经 实现了该”处理方法”,我们可以在运行时通过class_addMethod函数动态添加未知消息到类里面,让原来没有处理这个方法的类具有了处理这个方法的能力。

+(BOOL)resolveInstanceMethod:(SEL)sel
{

    //从系统里匹配SEL,如没有就注册SEL
    SEL systemSel = sel_registerName(sel_getName(sel));
    //把所有未知的SEL指向dynamicMethodIMP的实现,让dynamicMethodIMP帮忙打印错误信息,但是程序不会Cash
    class_addMethod(self,systemSel,(IMP)dynamicMethodIMP,"v@:");
    return [super resolveClassMethod:systemSel];
}

2.备用接收者

如果在动态方法解析无法处理消息,则Runtime会继续调以下方法:

-(id)forwardingTargetForSelector:(SEL)aSelector
{
    return [[Girl alloc] init];
}

3.完整转发

如果在上一步还不能处理未知消息,则唯一能做的就是启用完整的消息转发机制了。
此时会调用以下方法:

//在这里产生方法签名,以确保NSInvocation能被转发的Girl类执行,不然的话会出现错误
-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
    if (!signature) {
        if ([Girl instancesRespondToSelector:aSelector]) {
            signature = [Girl instanceMethodSignatureForSelector:aSelector];
        }
    }
    return signature;
}
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
    if ([Girl instancesRespondToSelector:anInvocation.selector]) {
        [anInvocation invokeWithTarget:[[Girl alloc] init]];//将消息转发给Girl对象
    }
}
-(id)forwardingTargetForSelector:(SEL)aSelector
{
    return [[Girl alloc] init];
}

消息传递机制

几个关键字含义

  • objc_msgSend()

    包含两个参数,第一个参数为接收消息的(对象),第二个参数为方法签名,之后为传递的参数,oc 运行时就是通过这个方法中的实例对象,通过isa指针找到对应的方法签名表,在找到执行的方法。

  • SEL

    SEL 可以理解为函数签名,通过@Selector(方法名)可以找到一个SEL类型对象,实际上是结构体指针,(也可以说成是一个hash表,通过方法名hash转换成的一个字符串)通过这个指针找到对应要执行的函数,也可以说是查找对应IMP。

  • IMP

    实际上是一个函数指针,指向方法实现的地址,上边说的SEL其实就是查找对应的IMP,可以理解为方法具体实现.

    id(*IMP)(id SEL, ...)
    
  • isa

    NSObject 中的class有一个 isa指针,isa 指针的作用就是找到对应的类,也可以是父类,元类,间接的找到对应函数地址等等。

消息查找机制涉及 实例类 父类 和 元类之间的关系

二. runtime 使用场景

以下为几个常见的使用场景,当然不止这些

1.发送消息

2.交换方法

+ (void)load {
/*
     self:UIImage
     谁的事情,谁开头 1.发送消息(对象:objc) 2.注册方法(方法编号:sel) 3.交互方法(方法:method) 4.获取方法(类:class)
     Method:方法名

     获取方法,方法保存到类
     Class:获取哪个类方法
     SEL:获取哪个方法
     imageName
*/
    // 获取imageName:方法的地址
    Method imageNameMethod = class_getClassMethod(self, @selector(imageNamed:));

    // 获取wg_imageWithName:方法的地址
    Method wg_imageWithNameMethod = class_getClassMethod(self, @selector(wg_imageWithName:));

    // 交换方法地址,相当于交换实现方式
    method_exchangeImplementations(imageNameMethod, wg_imageWithNameMethod);

}

3.动态添加方法

 WGStudent *student = [[WGStudent alloc] init];
 objc_msgSend(student, @selector(study));

4.给分类添加属性

通过关联实现

例子

UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
    btn.tag = 100;
    NSLog(@"%d",btn.tag);
    objc_setAssociatedObject(self, &overviewKey, btn, OBJC_ASSOCIATION_RETAIN);
    
    UIButton * btn1 = objc_getAssociatedObject(self, &overviewKey);
    btn1.tag  =111;
    NSLog(@"%d",btn1.tag);

static char flashColorKey;
- (void) setFlashColor:(UIColor *) flashColor{
    objc_setAssociatedObject(self, &flashColorKey, flashColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (UIColor *) getFlashColor{
    
    return objc_getAssociatedObject(self, &flashColorKey);
}



5.字典转模型

原文地址:https://www.cnblogs.com/keyan1102/p/7470079.html