标签:dispatch 建立 指针 return 协议 tail 很多 sdi bool
前言
KVO全称为Key Value Observing,键值监听机制,由NSKeyValueObserving协议提供支持,NSObject类继承了该协议,所以NSObject的子类都可使用该方法。
文章中的Demo
KVO监听写法
例如在XZPerson类中有这么几个属性
@interface XZPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nick;
@property (nonatomic, copy) NSString *downloadProgress;
@property (nonatomic, assign) double writtenData;
@property (nonatomic, assign) double totalData;
@property (nonatomic, strong) NSMutableArray *dateArray;
@property (nonatomic, strong) XZStudent *st;
@end
1.我们要监听name属性写法如下
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [XZPerson new];
[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"XZController--%@",change);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.person.name = @"alan";
}
在touchBegan方法中变化name值,observeValue中会得到变化;
这里如果我们要监听另一个XZStudent 继承于XZPerson类的并实现单利中也有name属性呢,很多人写法和上面一样,然后通过keyPath 来进行判断处理不同事项,
@interface XZStudent :XZPerson
+ (instancetype)shareInstance;
@end
@implementation XZStudent
static XZStudent* _instance = nil;
+ (instancetype)shareInstance{
static dispatch_once_t onceToken ;
dispatch_once(&onceToken, ^{
_instance = [[super allocWithZone:NULL] init] ;
}) ;
return _instance ;
}
@end
我来介绍另一种使用context 进行标记,官网上介绍,使用context更加安全,方便
static void *PersonNameContext = &PersonNameContext;
static void *StudentNameContext = &StudentNameContext;
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [XZPerson new];
self.student = [XZStudent shareInstance];
[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:PersonNameContext];
// 1. 使用context进行标记,更安全,更加便利
[self.student addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:StudentNameContext];
}
//回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
//context
if (context == PersonNameContext) {
NSLog(@"XZController--person -->%@",change);
}else if(context == StudentNameContext)
{
NSLog(@"XZController--person -->%@",change);
}else{
NSLog(@"XZController--%@",change);
}
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.person.name = @"alan";
self.student.name = @"alanStudent";
}
如果有XZController中监听了XZStudent的name属性,下级界面XZDetailController中也监听XZStudent的name属性,这个时候,如果在delloc中没有释放的话,返回后XZController中修改name值时就会报野指针,所以切记delloc中一定要进行析构释放
- (void)dealloc
{
[self.person removeObserver:self forKeyPath:@"name"];
[self.student removeObserver:self forKeyPath:@"name"];
}
2.如果需求多变,我们需要频繁更换监听值时
1.可以先把自动监听去掉automaticallyNotifiesObserversForKey 返回NO
2.然后需要监听那个值在值改变前后添加willChangeValueForKey,和didChangeValueForKey方法这个可以写入到set方法中
例如:添加上automaticallyNotifiesObserversForKey(慎用)方法后其他的监听不会自动触发
自动开关,设置为NO后,需要手动触发Willchange和didchange
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key{
return NO;
}
- (void)setNick:(NSString *)nick{
[self willChangeValueForKey:@"nick"];
_nick = nick;
[self didChangeValueForKey:@"nick"];
}
3.监听下载进度时,实际需要在写入进度和总进度这两个进行变化时触发下载进度
首先在XZPerson类中实现复合嵌套keyPathsForValuesAffectingValueForKey方法
// 下载进度 -- writtenData/totalData
+ (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{
NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
if ([key isEqualToString:@"downloadProgress"]) {
NSArray *affectingKeys = @[@"totalData", @"writtenData"];
keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
}
return keyPaths;
}
然后进行监听downloadProgress即可
- (void)dealloc
{
[self.person removeObserver:self forKeyPath:@"downloadProgress"];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [XZPerson new];
self.person.writtenData = 0;
self.person.totalData = 100;
[self.person addObserver:self forKeyPath:@"downloadProgress" options:NSKeyValueObservingOptionNew context:NULL];
}
}
//回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
//context
if (context == PersonNameContext) {
NSLog(@"XZController--person -->%@",change);
}else if(context == StudentNameContext)
{
NSLog(@"XZController--person -->%@",change);
}else{
NSLog(@"XZController--%@",change);
}
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.person.writtenData += 10;
self.person.totalData +=20;
}
打印结果:可以看出当writtenData变化时有变化,totalData变化时也有变化(这个场景主要用于下载任务,因为下载总任务量也是有可能进行持续添加的)
4.监听可变数组时
这里在变化的数组变化的写法上需要有些区别,而且需要在XZPerson类中添加如下方法:添加插入和删除方法
@implementation XZPerson
-(void)insertObject:(id)object inDateArrayAtIndex:(NSUInteger)index{
[self.dateArray insertObject:object atIndex:index];
}
-(void)removeObjectFromDateArrayAtIndex:(NSUInteger)index{
[self.dateArray removeObjectAtIndex:index];
}
@end
而且在变化值是也需要有所变化
- (void)dealloc
{
[self.person removeObserver:self forKeyPath:@"dateArray"];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [XZPerson new];
self.person.dateArray = [NSMutableArray array];
[self.person addObserver:self forKeyPath:@"dateArray" options:NSKeyValueObservingOptionNew context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
//context
if (context == PersonNameContext) {
NSLog(@"XZController--person -->%@",change);
}else if(context == StudentNameContext)
{
NSLog(@"XZController--person -->%@",change);
}else{
NSLog(@"XZController--%@",change);
}
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//数组变化这么写是不会监听到的
[self.person.dateArray addObject:@"1"];
//KVO 是建立在KVC
[[self.person mutableArrayValueForKey:@"dateArray"] addObject:@"2"];
}
可以看下打印结果:只有一次变化([self.person.dateArray addObject:@"1"];)这次变化没有监听到,注意写法
总结
这篇文章主要描述了一下KVO的简单实用,其中包括监听单个属性,监听多个变化属性,和监听可变数组的一些写法,希望对大家有用,后续文章会详细介绍KVO的底层实现,和自定义KVO的写法;
希望对大家有用处,欢迎大家点赞,关注我的CSDN,我会定期做一些技术分享!未完待续。。。
————————————————
原文链接:https://blog.csdn.net/ZhaiAlan/java/article/details/105813749
https://htcui.com/author/w6586114541/?tab=profile
https://htcui.com/author/w6586114731/?tab=profile
https://htcui.com/author/w6585723950/?tab=profile
https://htcui.com/author/w6585724100/?tab=profile
https://htcui.com/author/w6585724178/?tab=profile
https://htcui.com/author/w6585724275/?tab=profile
https://htcui.com/author/w6586114541/?tab
https://htcui.com/author/w6586114731/?tab
https://htcui.com/author/w6585723950/?tab
https://htcui.com/author/w6585724100/?tab
https://htcui.com/author/w6585724178/?tab
https://htcui.com/author/w6585724275/?tab
https://htcui.com/author/w6586114541
https://htcui.com/author/w6586114731
https://htcui.com/author/w6585723950
https://htcui.com/author/w6585724100
https://htcui.com/author/w6585724178
https://htcui.com/author/w6585724275
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E5%A8%B1%E4%B9%90%E5%B9%B3%E5%8F%B0%E4%BB%A3%E7%90%86__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E5%B9%B3%E5%8F%B0%E4%BB%A3%E7%90%86__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E4%BB%A3%E7%90%86_Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E5%A8%B1%E4%B9%90%E4%BB%A3%E7%90%86__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E6%80%BB%E4%BB%A3__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E5%B9%B3%E5%8F%B0%E6%80%BB%E4%BB%A3__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E5%A8%B1%E4%B9%90%E6%80%BB%E4%BB%A3__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E5%A8%B1%E4%B9%90%E5%B9%B3%E5%8F%B0%E6%80%BB%E4%BB%A3__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E6%80%BB%E4%BB%A3%E7%90%86__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E5%B9%B3%E5%8F%B0%E6%80%BB%E4%BB%A3%E7%90%86__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E5%A8%B1%E4%B9%90%E6%80%BB%E4%BB%A3%E7%90%86__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%B2%90%E9%B8%A3%E5%A8%B1%E4%B9%90%E5%B9%B3%E5%8F%B0%E6%80%BB%E4%BB%A3%E7%90%86__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%9D%8F%E9%91%AB%E4%BB%A3%E7%90%86_Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%9D%8F%E9%91%AB%E5%B9%B3%E5%8F%B0%E4%BB%A3%E7%90%86__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%9D%8F%E9%91%AB%E5%A8%B1%E4%B9%90%E4%BB%A3%E7%90%86__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%9D%8F%E9%91%AB%E5%A8%B1%E4%B9%90%E5%B9%B3%E5%8F%B0%E4%BB%A3%E7%90%86__Q%E3%80%901530667%E3%80%91
https://www.05jl.com/search/%E6%9D%8F%E9%91%AB%E6%80%BB%E4%BB%A3__Q%E3%80%901530667%E3%80%91
标签:dispatch 建立 指针 return 协议 tail 很多 sdi bool
原文地址:https://www.cnblogs.com/dasdfdfecvcx/p/12797354.html