深入剖析通知中心和KVO

深入剖析通知中心和KVO


要先了解KVO和通知中心,就得先说说观察者模式,那么观察者模式到底是什么呢?下面来详细介绍什么是观察者模式。
  • 观察者模式

      -A对B的变化感兴趣,就注册成为B的观察者,当B发生变化时通知A,告知B发生了变化,这就是观察者模式。
      观察者模式定义了一对一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有的观察者对象,使他们能够自动更新自己或者作出相应的一些动作。
      在开发中,我们可能会接触到观察者模式的实现方式,有NSNotificationCenter、KVO等。
    

下面就来上正菜了,在下面我会给大家详细讲解通知中心和KVO到底是什么,对于这两个,我也是模模糊糊,搞不清到底是什么东西,所以才找了资料,来整理整理,顺便写篇博客分享给大家。
  • 通知中心

    • 通知中心就是以NSNotificationCenter为中心,观察者往Center中注册对某个主题对象的变化感兴趣,主体对象通过NSNotificationCenter进行变化广播,所有的变化和监听行为都向同一个中心进行注册,所有对象的变化也通过同一个中心对外广播。

  • 通知中心的执行顺序

    • 通过NSNotificationCenter的addObserver:selector:name:object接口来注册通知中心

    • 被观察的对象,通过postNotificationName:object:userInfo:向通知中心发送某一类型通知。

    • 当有通知来的时候,Center会调用观察者注册的接口来广播通知,同时传递存储着更改内容的NSNotification对象。

    • 当该通知不再使用时,可以在dealloc方法里removeObserver:删除观察者

  • 代码

main.m

		//
		//  main.m
		//  通知中心
		//
		//  Created by ma c on 16/5/16.
		//  Copyright © 2016年 Jujue. All rights reserved.
		//
		
		#import <Foundation/Foundation.h>
		#import "Observer.h"
		#import "HttpClient.h"
		int main(int argc, const char * argv[]) {
		    @autoreleasepool {
		        // insert code here...
		        
		        //1、通知中心注册通知对象
		        //2、需要给通知中心发送消息的地方post通知
		        //3、执行注册通知时设置的方法
		        
		        Observer *observer = [[Observer alloc]init];
		        //在通知中心注册成为Observer的观察者
		        [observer registNotification];
		        
		        HttpClient *client = [[HttpClient alloc]init];
		        //发送消息
		        [client postNotifi];
		        
		    }
		    return 0;
		}

Observer.m

	 //
	//  Observer.m
	//  通知中心
	//
	//  Created by ma c on 16/5/16.
	//  Copyright © 2016年 Jujue. All rights reserved.
	//
	
	#import "Observer.h"
	
	@implementation Observer
	
	- (void)registNotification
	{
	    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
	    //注册成为观察者 观察对象是Observer 
	    [notificationCenter addObserver:self selector:@selector(doAction:) name:@"Observer" object:nil];
	}
	
	- (void)doAction:(NSNotification *)notifi
	{
	    //发送者是哪个类就输出的是什么东西-这个例子打印出来是 <HttpClient: 0x10020ead0>
	
	    NSLog(@"%@",notifi.object);
	    
	    //打印结果    name = xiaoyu;
	    NSLog(@"%@",notifi.userInfo);
	}
	
	- (void)dealloc
	{
	    [[NSNotificationCenter defaultCenter]removeObserver:self];
	}
	
	@end

HttpClient.m

//
//  HttpClient.m
//  通知中心
//
//  Created by ma c on 16/5/16.
//  Copyright © 2016年 Jujue. All rights reserved.
//

#import "HttpClient.h"

@implementation HttpClient


- (void)postNotifi
{
    NSDictionary *info = @{@"name":@"xiaoyu"};
    
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    
    [notificationCenter postNotificationName:@"Observer" object:self userInfo:info];
    
}

@end

KVO(键值观察)
  • KVO是一个典型的观察者模式,观察者在键值改变时会得到通知。iOS中有个Notification的机制,也可以获得通知,但这个机制需要有个Center,相比之下KVO更加简洁而直接。

  • NSKeyValueObserving非正式协议定义了一种机制,它允许对象去监听其它对象的某个属性的修改。NSObject提供了一个NSKeyValueObserving协议的默认实现,它为所有对象提供了一种自动发送修改通知的能力。我们可以通过禁用自动发送通知并使用这个协议提供的方法来手动实现通知的发送,以便更精确地去处理通知。

  • KVO的实现步骤

    • (1)注册需要观察的对象的属性addObserver:forKeyPath:options:context:

    • (2)实现observeValueForKeyPath:ofObject:change:context:方法,这个方法当观察的属性变化时会自动调用.在这个方法中还通过NSKeyValueObservingOptionNew这个参数要求把新值在dictionary中传递过来。

    • (3)取消注册观察removeObserver:forKeyPath:context:

  • 手动设置KVO

      //关闭某key值的KVO
      
      + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
          
          BOOL automatic = YES;
          if ([key isEqualToString:@"age"]) {
              automatic = NO;
          } else {
              automatic = [super automaticallyNotifiesObserversForKey:key];
          }
          return automatic;
      }
      
      //重写setter方法手动设置KVO
      
      - (void)setAge:(int)age {
          
          //手动设置KVO
          
          if (_age != age) {
              
              [self willChangeValueForKey:@"age"];
              
              _age = age;
              
              [self didChangeValueForKey:@"age"];
              
          }
      }
    

    注意:一般的建议是,在获取属性值时,可以用实例变量,在设置属性值时,尽量用setter方法,以保证属性的KVO特性。

  • KVO的实现原理

    • 当某一个类的实例第一次使用KVO的时候,系统就会在运行期间动态的创建该类的一个派生类,该类的命名规则一般是以NSKVONotifying为前缀,以原本的类名为后缀。并且将原型的对象的isa指针指向该派生类。同时在派生类中重载了使用KVO的属性的setter方法,在重载的setter方法中实现真正的通知机制,正如前面我们手动实现KVO一样。这么做是基于设置属性会调用 setter 方法,而通过重写就获得了 KVO 需要的通知机制。当然前提是要通过遵循 KVO 的属性设置方式来变更属性值,如果仅是直接修改属性对应的成员变量,是无法实现 KVO 的。

代码-大家可以去我的github去下载

KVO-Demo网址

posted @ 2016-05-17 22:33  往事亦如风  阅读(584)  评论(0编辑  收藏  举报