iOS------通知、代理、kvo 详解
通知:通知中心实际上是在程序内部提供了消息广播的一种机制。通知中心不能在进程间进行通信。实际上就是一个二传手,把接收到的消息,根据内部的一个消息转发表,来将消息转发给需要的对象。通知中心是基于观察者模式的,它允许注册、删除观察者。
一个 NSNotificationCenter 可以有许多的通知消息 NSNotification, 对于每一个 NSNotification 可以有很多的观察者 Observer 来接收通知。
委托代理:委托代理(degegate),顾名思义,把某个对象要做的事情委托给别的对象去做。那么别的对象就是这个对象的代理,代替它来打理要做的事。反映到程序中,首先要明确一个对象的委托方是哪个对象,委托所做的内容是什么。
委托机制是一种设计模式,在很多语言中都用到的,这只是通用的思想,网上会有很多关于这方面的介绍。
那么二者在开发的过程中,到底在什么情况下用何种方式更为方便和提高效率,根据笔者的开发经验总结一二,望大家不要见笑,有错误的地方,欢迎指正
通知的优势:通知使用起来非常方便,我们只需要在消息需要广播的地方发出去消息,至于消息内部怎么发的,我们不用管,只需要在我们想要得到这个消息的地方监听即可,不用管消息是怎么到这儿的。其实里面的原理也不是很复杂,大家有兴趣的可以自己研究。
通知的劣势:如果通知过多,会造成通知的管理复杂,如果管理不好,你会接收到莫名其妙的消息,而无法追踪。
代理的优势:首先,代理的效率要比通知高(个人见解),其实代理就是 c++ 里面的回调,调用我们都很明白,加上个回可能很多人都感觉迷糊了,其实也是调用,只是在我们直观的看的时候,感觉好像是我已经做过某件事情了,可是我们还能接收到已经过去一件事情的反馈,其实这个通知差不多,只是我们自己在已经做的事情里面去预先判断了某件可能发生的事情,然后主动的告诉我们,我们想要得到的某件事情。
代理的劣势:实现起来比较复杂,而且应用的场景没有通知多。
那么下面我们讨论下什么情况下用代理,什么情况下用通知 :
如果一个通知的发送者有多个接受者,而且接受的位置完全不确定,那么这种情况下用通知是比较好的方式。
如果一个类能够获取到通知的对象,这种情况下,我们用代理的效率会更高,而且能够更好的实现要代理的对象的管理。
代理的应用场景:
n对象A内部发生了一些事情,想通知对象B
n对象B想监听对象A内部发生了什么事情
n对象A想在自己的方法内部调用对象 B的某个方法,并且对象 A 不能对对象 B 有耦合依赖
n对象A想传递数据给对象 B
以上情况,结果都一样:对象 B 是 对象 A 的代理 (delegate)
n共同点
利用通知和代理都能完成对象之间的通信
(比如A对象告诉B对象发生了什么事情,A 对象传递数据给 D 对象)
n不同点
代理:一对一(1个对象只能告诉另1个对象发生了什么事情)
通知:多对多关系(1个对象能告诉 N 个对象发生了什么事情,1个对象能得知 N 个对象发生了什么事情)
KVO
KVO是一个对象能够观察另外一个对象的属性值,并且能够发现值的变化。kvo更加适合任何类型的对象侦听另外一个任意对象的改变,或者是一个对象与另外一个对象保持同步的一种方法,即当另外一种对象的状态发生改变时,观察对象马上作出反应。它只能用来对属性作出反应,而不会用来对方法或者动作作出反应。
kvo的优点 :
1、能够提供一种简单的方法实现两个对象间的同步;
2、能够对非我们创建的对象,即内部对象的状态改变作出响应,而且不需要改变内部对象(SDK对象)的实现;
3、能够获得观察的属性的最新值以及先前值;
4、用 key path 来观察属性,因此也可以观察嵌套对象(也就是可以观察一个对象内部对象的属性的变化,可以无限嵌套观察,前提是对象的属性支持kvo);
5、完成了对观察对象的抽象,因为不需要额外的代码来允许观察值能够被观察(不需要像通知一样还需要发送通知,kvo 属性的改变,外部可以直接观察)。
kvo的注意事项:
我们注册kvo的时候,要观察哪个属性,在调用注册方法的时候,addObserver: forKey: options: context : forKey 处填写的属性是以字符串形式,万一属性名字写错,因为是字符串,编译器也不会警告以及检查
kvo的使用:
被观察者发出 addObserver : forKey : options : context : 方法来添加观察者。然后只要被观察者的 keyPath 的值变化(注意:单纯改变其值不会调用此方法,只有通过 getters 和 setters 来改变值才会触发 kvo),就会在观察者里调用 observeValueForKeyPath : ofObject : change : context : 因此观察者需要实现方法 observeValueForKeyPath : ofObject : change : context ; 来对 kvo 发出的通知作出响应。
这些代码只需要在观察者里进行实现,被观察者不用添加任何代码,所以谁要监听谁注册,然后对响应进行处理即可,使得观察者与被观察者完全解耦,运用很灵活很简单,但是 kvo 只能检测类中的属性,并且属性名都是通过 NSString 来查找,编译器不会帮你检错和补全,纯手敲所以比较容易出错。