码迷,mamicode.com
首页 > 移动开发 > 详细

iOS 探索KVO一(几种简单的KVO使用方式)

时间:2020-04-28 21:33:12      阅读:89      评论:0      收藏:0      [点我收藏+]

标签: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

iOS 探索KVO一(几种简单的KVO使用方式)

标签:dispatch   建立   指针   return   协议   tail   很多   sdi   bool   

原文地址:https://www.cnblogs.com/dasdfdfecvcx/p/12797354.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!