isa指针
isa:是一个Class 类型的指针。 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调 用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。
同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass)。根元类的isa指针指向本身,这样形成了一个封闭的内循环。
KVC
KVC是键值编码,一种通过字符串间接访问对象的方式(即给属性赋值)
KVC的底层实现
当一个对象调用setValue方法时,方法内部会做以下操作:
1). 检查是否存在相应的key的set方法,如果存在,就调用set方法。
2). 如果set方法不存在,就会查找与key相同名称并且带下划线的成员变量,如果有,则直接给成员变量属性赋值。
3). 如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值。
4). 如果还没有找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。
这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
KVO
KVO(key-Value-Observing):键值观察机制,他提供了观察某一属性变化的方法。
使用KVO分为三个步骤:
1.通过addObserver:forKeyPath:options:context:方法注册观察者,观察者可以接收keyPath属性的变化事件。
2.在观察者中实现observeValueForKeyPath:ofObject:change:context:方法,当keyPath属性发生改变后,KVO会回调这个方法来通知观察者。
3.当观察者不需要监听时,可以调用removeObserver:forKeyPath:方法将KVO移除。需要注意的是,调用removeObserver需要在观察者消失之前,否则会导致Crash。
KVO的底层实现
KVO是基于runtime机制实现。
1.当一个类的属性首次被监听的时候,会在运行阶段生成一个新的派生类,对应的isa指针也会指向新的派生类,在这个派生类中被监听的属性的setter方法会增加willChangeValueForKey和didlChangeValueForKey方法。
2.当属性改变时,会调用willChangeValueForKey记录旧的值,然后属性值改变,接着调用didChangeValueForKey,这时kvo的observeValueForKeyPath就会被调用,实现监听的效果。
手动触发kvo
[self willChangeValueForKey:@"balance"];
_balance = theBalance;
[self didChangeValueForKey:@"balance"];
KVC会触发KVO吗
会,KVC的底层实现就是会先调用setter方法的。
访问并修改一个类的私有属性
1). 一种是通过KVC获取。
2). 通过runtime访问并修改私有属性。
消息转发
消息传递机制 objc_msgSend():接收者会根据isa指针找到接收者自己所属的类,然后在所属类的”方法列表“(method list)中从上向下遍历。如果能找到与选择子名称相符的方法,就根据IMP指针跳转到方法的实现代码,调用这个方法的实现。
如果找不到与选择子名称相符的方法,接收者会根据所属类的superClass指针,沿着类的继承体系继续向上查找(向父类查找),如果 能找到与名称相符的方法,就根据IMP指针跳转到方法的实现代码,调用这个方法的实现。
如果在继承体系中还是找不到与选择子相符的方法,此时就会执行消息转发操作。
消息转发(Message Forward):是Objective-C语言级别的特性,即Runtime的特性,也是Objective-C动态语言的特色之一。Objective-C Runtime会提供3次挽救的机会(准确的说是1次动态方法解析+2次消息转发;其中实例方法救3次,类方法救1次):
1、自己试下补锅(动态方法解析):+resolveInstanceMethod:(要处理类方法就是+resolveClassMethod:)
2、让别人来背锅:-forwardingTargetForSelector:
3、还是自己解决吧(包装成NSInvocation):-(void)forwardInvocation:(NSInvocation *)anInvocation
如果都没处理就会报异常然后程序崩溃,提示noRecognizeSelector,要让程序不崩溃的话可以在resolveInstanceMethod方法里添加统一的实现(里面使用到:class_addMethod:)
网友评论