KVO即:键值观察,直译为:基于键值的观察者。它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。
KVO的优点:当有属性改变,KVO会提供自动的消息通知。这样开发人员不需要自己去实现这样的方案:每次属性改变了就发送消息通知。这是KVO机制提供的最大的优点,因为这个方案已经被明确定义,获得框架级支持,可以方便地采用。开发人员不需要添加任何代码,不需要设计自己的观察者模型,直接可以在工程里使用。其次,KVO的架构非常的强大,可以很容易的支持多个观察者观察同一个属性,以及相关的值。
但我们都知道,使用KVO模式,对某个属性进行监听时,观察者需要在必要的时刻进行移除,否则应用必然会崩溃。这个问题有点烦的人,因为偶尔会忘记写移除观察者的代码…
<强>我一直想要这样一个效果:强>
只管监听,并处理监听方法。不去分心,管何时移除观察者,让其能够适时自动处理。
所幸,它能够实现,先预览一下:
@ interface NSObject (SJObserverHelper) - (void) sj_addObserver: (NSObject *)观察者forKeyPath: keyPath (NSString *); @end @ interface SJObserverHelper: NSObject @ property(原子,unsafe_unretained) id目标; @ property(原子,unsafe_unretained) id观察者; @ property(原子、强)NSString * keyPath; @ property(原子、弱)SJObserverHelper *因素; @end @ implementation SJObserverHelper - (void) dealloc { 如果(_factor) { [_target removeObserver: _observer forKeyPath _keyPath):; } } @end @ implementation NSObject (ObserverHelper) - (void) sj_addObserver: (NSObject *)观察者forKeyPath: (NSString *) keyPath { 【自我addObserver:观察者forKeyPath: keyPath选项:NSKeyValueObservingOptionNew上下文:nil); SJObserverHelper *辅助=(SJObserverHelper新); SJObserverHelper *子=(SJObserverHelper新); sub.target=助手。目标=自我; sub.observer=助手。观察者=观察者; sub.keyPath=助手。keyPath=keyPath; 帮手。因素=子; sub.factor=助手; const char * helpeKey=[NSString stringWithFormat: @ % zd,[观察者散列]].UTF8String; objc_setAssociatedObject(自我,helpeKey,助手,OBJC_ASSOCIATION_RETAIN_NONATOMIC); objc_setAssociatedObject(观察者,helpeKey子,OBJC_ASSOCIATION_RETAIN_NONATOMIC); } @end
项目源码
下面来说说一步一步的实现吧:
我们都知道,对象被释放之前,会调用dealloc方法,其持有的实例变量也会被释放。
我就这样想,在监听注册时,为自己和观察者关联个临时对象,当两者在释放实例变量时,我借助这个时机,在临时对象的dealloc方法中,移除观察者就行了。
想法很好,可总不能每个类里都加一个临时对象的属性吧。那如何在不改变原有类的情况下,为其关联一个临时对象呢& # 63;
不改变原有类,这时候肯定是要用类别了,系统框架里面有很多的分类,并且有很多的关联属性,如下图UIView头文件第180行:
# import & lt; objc/message.h> @ interface NSObject(副) @ property(原子、强)id tmpObj; @end @ implementation NSObject(副) 静态const char * testKey=皌estKey”; - (void) setTmpObj: (id) tmpObj {//objc_setAssociatedObject (id对象,const void *键,id值,objc_AssociationPolicy政策) objc_setAssociatedObject(自我、testKey tmpObj OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (id) tmpObj {//objc_getAssociatedObject (id对象,const void *键) 返回objc_getAssociatedObject(自我,testKey); } @end
很明确,objc_setAssociatedObject便是关联属性的setter方法,而objc_getAssociatedObject便是关联属性的getter方法。最需要关注的就是setter方法,因为我们要用来添加关联属性对象。
初步尝试: