iOS-底层原理- KVO的基本使用

2021-12-12  本文已影响0人  如意神王

1.KVO是做什么的

1.KVO : (Key - Value - Observer) 键值观察者,KVO全称KeyValueObserving,是苹果提供的一套事件通知机制。允许对象监听另一个对象属性的改变,并在改变时接收到事件。由于KVO的实现机制,所以对属性才会发生作用,一般继承自NSObject的对象都默认支持KVO。

\color{red}{2.KVO只能观察属性}

2.基本使用步骤

1.注册观察者
ViewController观察Person类name属性的变化 context参数提高可读性+便于回调方法区分

static void * PersonNameContext = &PersonNameContext;

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    self.m_person = [[Person alloc] init];
    self.m_person.name = @"LiLei";
    [self.m_person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:PersonNameContext];
}

2.实现回调方法
ViewController里面书写iOS系统的KVO回调方法

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if (context == PersonNameContext) {
        NSLog(@"keypath == %@", keyPath);
        NSLog(@"object == %@", object);
        NSLog(@"change == %@", change);
        NSLog(@"change[NSKeyValueChangeNewKey] == %@", change[NSKeyValueChangeNewKey]);
    }
}

3.修改被观察对象的属性值
touchBegan方法里修改self.m_person.name的属性值

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.m_person.name = [NSString stringWithFormat:@"%@+", self.m_person.name];
}

系统回调方法对应输出

2021-12-12 13:19:37.462142+0800 KVO_18_001_SBY[2215:100253] keypath == name
2021-12-12 13:19:37.462285+0800 KVO_18_001_SBY[2215:100253] object == <Person: 0x600002cf8a20>
2021-12-12 13:19:37.462460+0800 KVO_18_001_SBY[2215:100253] change == {
    kind = 1;
    new = "LiLei+";
}
2021-12-12 13:19:37.462562+0800 KVO_18_001_SBY[2215:100253] change[NSKeyValueChangeNewKey] == LiLei+

4.移除观察者
合适的位置移除观察者

- (void)dealloc {
    [self.m_person removeObserver:self forKeyPath:@"name" context:PersonNameContext];
}

3.KVO使用小细节

1.禁止观察某个属性值,系统默认是YES而且不用书写出来,如果返回NO的话name这个属性值就观察不了了,每个属性都有一个是否自动观察的方法

// 默认是YES可以观察并且没有这行代码 name属性,返回NO的时候观察不了了
+ (BOOL)automaticallyNotifiesObserversOfName {
    return NO;
}

2.手动观察属性
即使automaticallyNotifiesObserversOfName返回NO,关闭自动观察,手动打开下面的代码依然可以观察

- (void)setName:(NSString *)name {
    [self willChangeValueForKey:@"name"];
    _name = name;
    [self didChangeValueForKey:@"name"];
}

3.观察数组,修改属性值的时候需要用[self.m_person mutableArrayValueForKey:@"dateArray"],不能self.m_person.dateArray

self.m_person.dateArray = [NSMutableArray arrayWithCapacity:0];
[self.m_person addObserver:self forKeyPath:@"dateArray" options:NSKeyValueObservingOptionNew context:PersonNameContext];
[[self.m_person mutableArrayValueForKey:@"dateArray"] addObject:[NSString stringWithFormat:@"%lu", (unsigned long)count]];

4.复合观察、路径观察,多个属性合并成一个属性进行观察

[self.m_person addObserver:self forKeyPath:@"downloadProgress" options:NSKeyValueObservingOptionNew context:PersonNameContext];
// 下载进度 -- writtenData/totalData,这两个值的观察变成一个值downloadProgress的观察
+ (NSSet <NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
    NSSet * keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
    if ([key isEqualToString:@"downloadProgress"]) {
        NSArray * affectingKeys = @[@"totalData", @"writtenData"];
        keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
    }
    return keyPaths;
}

// 复合路径的开关,默认是YES可以不书写,如果返回NO,不能观察downloadProgress属性
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
    return YES;
}
self.m_person.writtenData += 10;
self.m_person.totalData = 100;

输出

2021-12-12 14:14:33.304174+0800 KVO_18_001_SBY[1006:28002] keypath == downloadProgress
2021-12-12 14:14:33.304275+0800 KVO_18_001_SBY[1006:28002] object == <Person: 0x6000028750e0>
2021-12-12 14:14:33.304397+0800 KVO_18_001_SBY[1006:28002] change == {
    kind = 1;
    new = "0.100000";
}
2021-12-12 14:14:33.304475+0800 KVO_18_001_SBY[1006:28002] change[NSKeyValueChangeNewKey] == 0.100000
2021-12-12 14:14:33.304549+0800 KVO_18_001_SBY[1006:28002] keypath == downloadProgress
2021-12-12 14:14:33.304616+0800 KVO_18_001_SBY[1006:28002] object == <Person: 0x6000028750e0>
2021-12-12 14:14:33.304700+0800 KVO_18_001_SBY[1006:28002] change == {
    kind = 1;
    new = "0.100000";
}
2021-12-12 14:14:33.304748+0800 KVO_18_001_SBY[1006:28002] change[NSKeyValueChangeNewKey] == 0.100000
2021-12-12 14:14:33.304809+0800 KVO_18_001_SBY[1006:28002] keypath == downloadProgress
2021-12-12 14:14:33.304856+0800 KVO_18_001_SBY[1006:28002] object == <Person: 0x6000028750e0>
2021-12-12 14:14:33.304950+0800 KVO_18_001_SBY[1006:28002] change == {
    kind = 1;
    new = "0.100000";
}
2021-12-12 14:14:33.305008+0800 KVO_18_001_SBY[1006:28002] change[NSKeyValueChangeNewKey] == 0.100000
上一篇下一篇

猜你喜欢

热点阅读