观察者模式-KVO与通知

观察者模式

在这里插入图片描述
Observer 观察者模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在更改其状态时,会通知所有的观察者对象,使他们能够自动更新自己。一个主题对象可以对应多个观察者,而这些观察者之前没有相互联系,可以根据需要增加和删除观察者,使得系统更易于拓展。

NSNotificationCenter

NSNotificationCenter 和 NSNotificationiOS 中的通知机制是非常典型的观察者模式,所有的类可以通过 NSNotificationCenter 监听和发送 NSNotification,观察者和被观察者都无需知晓对方,只需要通过标记(例如 NotificationName)在 NSNotificationCenter 中找到监听该通知所对应的类,从而调用该类的方法。并且,在 NSNotificationCenter 中,观察者可以只订阅某一特定的通知,并对其做出响应,而不用对某一个类发送的所有通知都进行更新操作。NSNotificationCenter 对观察者的调用不是随机的,而是遵循注册顺序一一执行,并且在该线程内是同步的。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notice:) name:@"tongzhi" object:nil];

-(void)notice:(id)sender{  
  NSLog(@"%@",sender);
}
[[NSNotificationCenter defaultCenter] postNotificationName:@"tongzhi" object:nil];

使用对象来发消息

//发通知

-(void)btn2Click:(UIButton *)btn

{

[[NSNotificationCenter defaultCenter] postNotificationName:@"noti2" object:[NSString stringWithFormat:@"%@",btn.titleLabel.text]];

}

//监听

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(noti2:) name:@"noti2" object:nil];

//调用方法

-(void)noti2:(NSNotification *)noti

{

//使用object处理消息

NSString *info = [noti object];

NSLog(@"接收 object传递的消息:%@",info);

}

使用userinfo来发消息

//发通知

-(void)btn3Click

{

NSDictionary *dic = [NSDictionary dictionaryWithObject:@"userInfo消息" forKey:@"param"];

[[NSNotificationCenter defaultCenter] postNotificationName:@"noti3" object:nil userInfo:dic];

}



//监听

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(noti3:) name:@"noti3" object:nil];

//调用方法

-(void)noti3:(NSNotification *)noti

{

//使用userInfo处理消息

NSDictionary  *dic = [noti userInfo];

NSString *info = [dic objectForKey:@"param"];

NSLog(@"接收 userInfo传递的消息:%@",info);

}

和delegate相比,是更大跨度的通讯机制。

KVO是什么

KVO: 全称 Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变。
在这里插入图片描述
如图所示,当被监听者的被监听内容发生变化时,会调用监听者的observeValueForKeyPath
我们打个断点,看看添加kvo前后对象的变化。
在这里插入图片描述
实例对象的isa指针指向父类,添加了观察者后,从Person变成了NSKVONotifying_Person.
我们重写set方法,查看调用栈
没有添加观察者
在这里插入图片描述
添加了观察者后:
在这里插入图片描述
先调用的是这个NSSetObjectValueAndNotify函数,而我们打印setString的地址
NSLog(@"%p", [person methodForSelector:@selector(setString:)]);
然后取它的imp
在这里插入图片描述
也就是说,添加了监听的set方法实现变成了这个。
因为我们是为对象添加了监听,其实还有许多方法
在这里插入图片描述
既然它重写了set方法,那么它会不会也重写了其他方法

 Class cls = object_getClass(person);
    unsigned int count ;
        Method *methods = class_copyMethodList(cls, &count);
        NSMutableString *methodNames = [NSMutableString string];
        [methodNames appendFormat:@"%@ - ", cls];
        
        for (int i = 0 ; i < count; i++) {
            Method method = methods[i];
            NSString *methodName  = NSStringFromSelector(method_getName(method));
            
            [methodNames appendString: methodName];
            [methodNames appendString:@" "];
            
        }
        
        NSLog(@"%@",methodNames);
        free(methods);

打印结果:

NSKVONotifying_Person - setString: class dealloc _isKVOA

它把class也重写了,所以我们调用class方法返回的是Person而不是上面提到的类。
我们猜测它修改了class方法是:

- (Class) class {
     // 得到类对象,在找到类对象父类
     return class_getSuperclass(object_getClass(self));
}

因为实例调用superclass会先调用class方法再调用superclass,所以我们打印superclass是NSObject。
在这里插入图片描述
在此,NSKVONOtifying_Person应该是Person的子类。
原博客图片:
在这里插入图片描述

_NSSetIntValueAndNotify

验证didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法
我们在Person类中重写willChangeValueForKey:和didChangeValueForKey:方法,模拟他们的实现。

willChangeValueForKey: - begin
2020-08-11 21:20:32.040307+0800 KVO探索[6736:18622244] willChangeValueForKey: - end
2020-08-11 21:20:32.040396+0800 KVO探索[6736:18622244] setString
2020-08-11 21:20:32.040475+0800 KVO探索[6736:18622244] didChangeValueForKey: - begin
2020-08-11 21:20:32.040595+0800 KVO探索[6736:18622244] success

先调用了willChangeValueForKey 然后是set方法,然后调用didChangeValue,然后调用observeValue方法。

手动触发KVO

手动调用willChangValueForKey和didChangeValue。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值