KVO(键值监听)
iOS推荐的设计模式是MVC,Model View Controller。KVO和下面的通知用于Model和Controller之间通信,(在MVC中,Model和Controller不能通信).
KVO机制由NSKeyValueObserving协议提供支持,NSObject遵守了该协议,所有OC的类都可以使用协议中的方法,里面的方法有:
addObserver:<#(nonnull NSObject *)#> forKeyPath:<#(nonnull NSString *)#> options:<#(NSKeyValueObservingOptions)#> context:<#(nullable void *)#>];
observer:观察对象,需要实现observeValueForKeyPath: ofObject: change: context:。
keyPath:被观察的属性。
options:发送通知的时机(属性值改变前or改变后通知)
context:(目前未用到过该参数)上下文信息,通常为nil。
NSKeyValueObservingOptions:
NSKeyValueObservingOptionNew 返回新值
NSKeyValueObservingOptionOld 返回旧值
NSKeyValueObservingOptionInitial 注册的时候发一次通知,改变后也发送一次通知
NSKeyValueObservingOptionPrior 改变之前发一次,改变之后再发一次
A addObserver: B
添加A的观察者B,当A的属性(后边的参数forKeyPath填 @“A的属性”)发生改变的话,会激活一个方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
//该方法里的参数:
//keyPath 变化的属性
// object 变化的对象 (比如我们修改的是UIlabel的text,打印这个Object会返回UIlabel的信息
// change是一个字典,里面有修改后的属性值,可以自行打印一下
}
所以步骤为:
1⃣️为被监听对象注册监听器
2⃣️重新上面的方法
3⃣️在delloc里移除该监听器
- 移除的方法是 removeObserve:forKeyPath:
通知
NSNotification 解决的问题
可以实现跨层的传递,例如A页面跳转到B页面,B页面再跳转到C页面,这时候如果我们通过委托回调的模式让A知道C的一些修改,那么实现起来就会很麻烦。
可以实现一对多,NSNotification 的实际是一种观察者模式
。
每一个 iOS 程序都有一个唯一的通知中心,不必自己去创建一个,它是一个单例,通过 [NSNotificationCenter defaultCenter] 方法获取。
NSNotification 不能通过 init 实例化
- NSNOtificationCenter相当于广播站,可以注册观察者和注销(注册和注销次数不一致会crash),每个post的通知是由通知中心发出的,转发给监听者。
- 在 NSNotificationCenter 注册观察者,发送者使用通知中心广播时,以 NSNotification 的 name 和 object 来确定需要发送给哪个观察者。为保证观察者能接收到通知,所以应先向通知中心注册观察者,接着再发送通知这样才能在通知中心调度表中查找到相应观察者进行通知。
- iOS 9 NSNotificationCenter 无需手动移除观察者
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(landSuccessful:) name:@"landSuccessfule" object:nil];
//添加当前对象为观察者(当前对象接收通知)收到名字为:@"landSuccessful"通知执行landSuccessful方法.object为nil,表示接受任何对象的通知,如果name为nil表示接受任何name的通知
//一般在controller注册观察者
//在model发出通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"landSuccessful" object:self];
通知中心发出名称为landSuccessful的通知,发送者是self,也就是model。
消息队列还未涉猎
代理
代理传值用在不同的controller之间,例如用户输入了字符串,view是controller的属性,controller可以轻松拿到它,但是另外一个controller如何得到它,得依靠代理实现。
//定义协议与方法
@protocol DeliverDetegate <NSObject>
- (void)setValue:(NSString *)string;
@end
@interface BViewController : UIViewController
//声明委托变量
@property (weak,nonatomic) id<DeliverDetegate>B_Delegate;
@end
//(题外话)我们在一个controllerA push到另外一个controllerB的时候(将B中的数据返回给A),需要设置代理->B的代理设置为A,这时候A就已经遵守了传值协议,但是如果在A的.h文件不写的话会报警告.
下面的demo会演示如何使用代理传值。
MVC
model、view、controller三者。
mode不能与View通信,controller与mode和View通信。
model负责数据处理,View负责用户界面显示。contoroller传递用户交互信息,数据处理信息
具体由我下面的demo来展示。
github地址