简述NotificationCenter、KVC、KVO、Delegate?并说明它们之间的区别?

219 阅读4分钟

Notification:

-观察者模式,controller向DefaultNotificationCenter添加自己的 notification,其他类注册这个notification就可以收到通知,这些类可以在收到通知时做自己的操作(多观察者默认随机顺序发通知给 观察者们,而且每个观察者都要等当前的某个观察者的操作做完才能轮到他来操作,可以用NotificationQueue的方式安排观察者的反应顺序,也 可以在添加观察者中设定反映时间,取消观察需要在viewDidUnload 跟dealloc中都要注销);

KVC

-键值编码, 可以直接通过字符串的名字(key)来间接访问属性的机制,而不是通过调用getter和setter方法访问;

KVO:

-观测指定对象的属性,当指定对象的属性更改之后会通知相应的观察者;

delegate:

-一对一,delegate遵循某个协议并实现协议声明的方法;

NSNotification实现原理

原理

KVC

基本使用的方法有:

  • (nullableid)valueForKey:(NSString*)key;//通过Key来取值

  • (void)setValue:(nullableid)value forKey:(NSString*)key;//通过Key来设值

  • (nullableid)valueForKeyPath:(NSString*)keyPath;//通过KeyPath来取值(对象包含对象这种情况)

  • (void)setValue:(nullableid)value forKeyPath:(NSString*)keyPath;//通过KeyPath来设值

在设置或者取值的时候默认情况下会根据:_key->_iskey->key->iskey的顺序搜索成员

除非:

  • (BOOL)accessInstanceVariablesDirectly; 

这个方法重写返回NO。(是否可以直接访问成员变量)

设置值的实现:

如果这个方法返回设置成NO,设置值的时候会去看setKey:这个方法,如果没找到则直接调用

  • (void)setValue:(id)value forUndefinedKey:(NSString*)key 这个方法

如果返回设置或者默认是YES,那么没有找到setKey:_setKey:或者 setIsKey: 这个方法时会继续向下搜索按照这个顺序寻找:_key->_iskey->key->iskey搜索成员。

KVO

首先需要了解KVO基本使用,KVO的全称 Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变。KVO:key-value observing,是在KVC基础上实现的,当某个对象的属性发生改变时,通知其它对象的机制。仅仅在以KVC准则来访问访问器或实例变量的情况下,才可以监视属性的变化。在方法内直接改变实例变量的值时,就不能监视了 参考实现原理


- (void)viewDidLoad{
  //添加观察者
  _person = [[Person alloc] init];
  [_person addObserver:self
          forKeyPath:@"age"
             options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
             context:nil];
}

//KVO回调方法
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSString *,id> *)change
                       context:(void *)context 
{
    NSLog(@"%@对象的%@属性改变了,change字典为:%@",object,keyPath,change);
    NSLog(@"属性新值为:%@",change[NSKeyValueChangeNewKey]);
    NSLog(@"属性旧值为:%@",change[NSKeyValueChangeOldKey]);
}

//移除观察者
- (void)dealloc
{
    [self.person removeObserver:self forKeyPath:@"age"];
}

delegate

代理的基本使用

代理是一种通用的设计模式,在iOS中有特定的语法来实现代理模式,OC语言可以通过@Protocol实现协议。

代理主要由三部分组成:

协议:用来指定代理双方可以做什么,必须做什么。

代理:根据协议,完成委托方需要实现的功能(方法)。

委托:根据协议,指定代理去完成什么功能。

协议(Protocol)的概念

概念

从上图中我们可以看到三方之间的关系,在实际应用中通过协议来规定代理双方的行为,协议中的内容通常情况都是方法列表,当然也可以定义属性.(后面会介绍协议属性)协议是公共的,如果只是单单某个类去使用,我们常做的就是写在某个类中。如果多个类都是使用同一个协议,这里建议大家创建一个Protocol文件,在这个文件中制定协议。遵循的协议可以被继承,!

例如:UITableView,继承自UIScrollView,所以也将UIScrollViewDelegate继承了过来,这样我们就可以通过代理方法获取UITableView偏移量等状态参数。 协议只能定义公用的一套接口,类似于一个约束代理双方的作用。但不能提供具体的实现方法,实现方法需要代理对象(可以理解为接受协议遵守协议的代理人)去实现。 协议可以继承其他协议,也可以继承多个协议,在iOS中对象是不支持多继承的,而协议是可以多继承。 协议有两个修饰符@optional@required,创建一个协议如果没有声明修饰符,默认是@required状态的。这两个修饰符只是约定代理是否强制需要遵守协议,如果@required状态的方法代理没有遵守,Xcode会报一个黄色的警告,@required是需要我们必须实现的。@optional是可以选择实现的.

参考实现原理