iOS观察者模式的底层实现

KVO(Key Value Observing, 键值观察)是一种设计模式,是Objective-C对观察者模式的实现,每次当被观察对象的某个属性值发生改变时,注册的观察者便能获得通知。

使用KVO很简单,分为三个基本步骤:

①、注册观察者,指定被观察对象的属性:

 [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];

通知其他对象的方法,这个方法在NSObject中就已经申明了,也就是说任何继承自NSObject的对象都可以使用KVO.

②、在观察者中实现以下回调方法:

  - (void)observeValueForKeyPath:(NSString *)keyPath  
     ofObject:(id)object  
                    change:(NSDictionary *)change  
                   context:(voidvoid *)context  
     {  
        // use the context to make sure this is a change in the address,  
        // because we may also be observing other things 

        NSString *name = [object valueForKey:@"name"]; 
        NSLog(@"new name is: %@", name);  
    }  

只要person对象中的name属性发生变化,系统会自动调用该方法。

③、最后,不要忘记在dealloc中移除观察者

-(void)dealloc  
{  
      // must stop observing everything before this object is  
      // deallocated, otherwise it will cause crashes  
      for(Person *p in m_observedPeople){  
          [p removeObserver:self forKeyPath:@"name"];  
      }  

      [m_observedPeople release];  
      m_observedPeople = nil;  
  }  

注意:添加的观察者的次数要和移除观察者的次数相等,少移除一个或者多移除一个都会造成程序崩溃:

1、KVO的实现原理:

当设置一个类为观察对象时,系统会动态地创建一个新的类,这个新的类继承自被观察对象的类,还重写了基类被观察属性的setter方法。派生类在被重写的setter方法中实现真正的通知机制。最后,系统将这个对象的isa指针指向这个新创建的派生类,这样,被观察对象就变成了新创建的派生类的实例。(注:runtime中,对象的isa指针指向该对象所属的类,类的isa指针指向该类的metaclass。有关OC的对象、类对象、元类对象metaclass object和isa指针,请戳这里详细了解)。同时,新的派生类还重写了dealloc方法(removeObserver)。

2、KVO的缺陷

不可否认,KVO的功能确实很强大,但是它的缺点也很明显:

①、过于简单的API

KVO中只有通过重写-observeValueForKeyPath:ofObject:change:context方法来获取通知,该方法有诸多限制:不能使用自定义的selector,不能使用block,而且当父类也要监听对象时,往往要写一大坨代码。

②、父类和子类同时存在KVO时(监听同一个对象的同一个属性),很容易出现对同一个keyPath进行两次removeObserver操作,从而导致程序crash。要避免这个问题,就需要区分出KVO是self注册的,还是superClass注册的,我们可以在 -addObserver:forKeyPath:options:context:和-removeObserver:forKeyPath:context这两个方法中传入不同的context进行区分。

你可能感兴趣的:(iOS观察者模式的底层实现)