谈一谈OC运行时同信息转发

运行时

网上对运作时机制暴发这一个含糊的传教,但相信如故会发生成千上万丁连无净了然运行时之机制。那么什么是运作时为?
先来拘禁无异栽写法:

@interface MyClass : NSObject 
{
    @public
        NSString *_myName;
    @private
        NSString *_myID;
}

OC中凡支撑public和private关键字的,类似于java或C#,然而咱以编写OC代码的时节也特别少这么做。因为使用这种写法,对象布局在编译器就既固化了。只要碰着访问_myName变量的代码,编译器就拿该替换为偏移量(offset),那个偏移量是硬编码,表示该变量距离存放对象的内存区域的胚胎地址发生差不多少距离。可是假若当运行过程遭到,又新增了一个实例变量,硬编码于其中的变量就会合宣读到左的值,例如大家只要每个变量的指针都是4单字节,新增一个变量myGender:

@interface MyClass : NSObject 
{
    @public
        NSString *_MyGender;(offset为0)
        NSString *_myName;(offset为+4)
    @private
        NSString *_myID;(offset为+8)
}

就算offset采纳硬编码,原类中offset为0凡是应该访问到_myName现在也看到_myGender。
OC的做法是,把实例变量当做一种存储offset所用之独特变量,交由类似对象保管。offset会以运行期查找,假若类似的定义变了,那么offset也会相应改变,这样的话,无论啥时候造访实例变量,总能访问到科学的晃动地点。
C语言,顿时即便是大家所说之周转时机制。想重新深远的问询运行时机制可以望这篇稿子:
http://quotation.github.io/objc/2015/05/21/objc-runtime-ivar-access.html
当即篇稿子以解释了为何OC不可能动态增长成员变量。

信转发

还来说同样游说信息转发,音讯转发是运作时机制的等同分外特征。在摸底信息转发在此之前先行来精晓一个OC的底部函数:

void objc_msgSend(id self, SEL cmd, ...)

于OC中,所有的方最后还会师转移为常见的C语言函数,例如一个对象object的道:

- (id)doSomething:(id)parameter
{
    //doSomething
}

叫object发送信息:

id returnValue = [object doSomething:patameter];

object是接受者,doSomething叫做选拔子,选拔子与参数合起来称音信,编译器看到是信息后,会将该更换为同长条标准的C语言函数,就是太起头之坏函数,它是音信传递机制中的主干函数,上述音信会转换为:

id returnValue = objc_msgSend(object,@selector(doSomething:),parameter);

objc_msgSend函数会按照接受者与采取子的品类来调用适当的措施。为了成功这操作,该法需要在接受者所属之近乎中找方法列表,假设找到了号符合的格局,就跳反至该落实代码,固然搜索不顶,就沿着继承类别向上查找。所过最后还是没找到符合的点子,就相会履行信转发
一个完的信转发过程会更五只级次:

  • 动态方法分析(resolveInstanceMethod或resolveClassMethod)
  • 备接收者(forwardingTargetForSelecor)
  • 完消息转发(forwardInvocation)

</br>

1. 动态方法分析

在信转发起首通常,本类有机会新增一个甩卖拔取子的方,假设采取子是实例方法会调用:

+ (BOOL)resolveInstanceMethod : (SEL)selector

如若是类似模式,则会调用:

+ (BOOL)resolveClassMethod : (SEL)selector

比如,用此方案来实现@dynamic属性:

id autoDictionaryGetter(id self, SEL _cmd);
id autoDictionarySetter(id self, SEL _cmd, id value);

+ (BOOL)resolveInstanceMethod:(SEL)selector
{
    NSString *selectorString = NSStringFromSelector(selector);
    if (/*选择子是个@dynamic属性*/)
        if ([selectorString hasPrefix:@"set"]) {
            class_addMethod(self, selector, (IMP)autoDictionarySetter, "v@:@");
        } else {
            class_addMethod(self, selector, (IMP)autoDictionaryGetter, "@@:");
        }
        return YES;
    }
    return [super resolveInstanceMethod:selector];
}

倘前缀为set,就是set方法,否则是get方法。不管啊种情状,都汇合拿拍卖该接纳子的道动态的加到类里面,以无比当最先拍卖音讯转发。例子中因故到了IMP指针,想精晓IMP指针可以望这篇博客:
http://www.jianshu.com/p/425a39d43d16?utm\_campaign=maleskine&utm\_content=note&utm\_medium=writer\_share&utm\_source=weibo

2. 准备接收者

假若在动态方法分析时未尝拍卖信息转发,那么还有第二次机会来拍卖未知的挑三拣四择子,在即时无异于步着网会明白:有没有发出其它接收者来拍卖当下长长的信息?该手续对应之拍卖措施如下:

- (id)forwardingTargetForSelector:(SEL)selector

然咱不可以操作由这无异步所转发的音,假诺想在殡葬给准备接受者在此以前先行改音讯内容,就得经过一体化的信息转发机制来开了。

3. 完好无损的音讯转发

先是,成立NSInvacation对象,把同无处理的那么长音讯有关的整整细节都封闭装在里头,此指标包括采取子,target及参数。在触发NSInvocation对象时,音信转发系统以亲自出马,把信使给目标靶。
以此过程会调用:

- (void)forwardInvocation:(NSInvocation *)invocation

此点子可以兑现之百般简单:只要改变调用target,使信息于新targer上得调用即可。可是如此的贯彻即与准备接受者的落实模式齐学了。一般的做法是:在点音讯前,先以某种情势转音信内容,比如扩大此外一个参数,或又改拔取子等等。
兑现这道时,若发现调用操作不答应由本类处理,则需要调用超类的同名方法。这样的话,继承系列中的每个接近都暴发时机处理这调用请求,直至NSObject。假若最终这多少个音不得到处理,则会调用NSObject的doesNotRecognizeSelector:,以废来好。
完的消息转发用到NSInvocation对象,想询问NSInvocation可以关押无异禁闭这首博文:
http://mp.weixin.qq.com/s?\_\_biz=MjM5NTIyNTUyMQ==&mid=208927760&idx=1&sn=30b9caecba709553e463d719668454ae&scene=2&from=timeline&isappinstalled=0\#rd

4. 整机的信转发流程图

C语言 1

除此以外需要注意的凡,音信转发过程被,步骤越向后,处理消息的代价就是一发老,最好会以第一步就是处理完毕,这样的话,运行期系统可以以这办法缓存。如若这仿佛的实例还会再接过及跟名采用子,那么从毫无再启航新闻转发流程。
除此以外一首介绍运行时机制的博文:
http://www.cocoachina.com/ios/20150715/12540.html