iOS自动移除KVO观察者的实现方法

  

  

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行:
  

  

 iOS自动移除KVO观察者的实现方法”> <br/>
  </p>
  <p>依照上的图,我们先看一个示例,为NSObject的添加一个类别,并添加了一个属性,在m中实现了它的setter和getter方法。</p>
  
  <pre类=   # 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方法,因为我们要用来添加关联属性对象。

  

  

初步尝试:
  

  

iOS自动移除KVO观察者的实现方法