iOS面试准备

iOS中kvo相关应用

2020-04-18  本文已影响0人  楼上那只猫

什么是kvo?
一句话:kvo是一种机制,可以允许一个对象去监控另一个对象的属性变化,并且在属性变化时得到通知。

Key-value observing is a mechanism that allows objects to be notified of changes to specified properties of other objects.

如何取消系统自动发送的通知,而手动控制?
假设Person类的firstName属性被监控,当其发生变化的时候,我们想手动控制什么时候发出通知,或者在发出通知前做其它操作,那么需要在Person中重写如下方法。

- (void)setFirstName:(NSString *)firstName {
    // 必须手动调用
    [self willChangeValueForKey:@"firstName"];
    _firstName = firstName;
    NSLog(@"xxxx");
    // 必须手动调用
    [self didChangeValueForKey:@"firstName"];
}

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
    if ([key isEqualToString:@"firstName"]) {
        return NO;
    }
    return YES;
}

如果被监控的属性的变化受到多个其它属性的影响,如何实现?
如果Person中的fullName被监控,但是fullName的值受到firstName和lastName的影响。

- (NSString *)name {
    return [NSString stringWithFormat:@"%@%@", _firstName, _lastName];
}

+ (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
    NSSet * keypath = [super keyPathsForValuesAffectingValueForKey:key];
    if ([key isEqualToString:@"name"]) {
        // 指定影响name变化的属性有哪些
        NSArray * effectKeys = @[@"firstName", @"lastName"];
        keypath = [keypath setByAddingObjectsFromArray:effectKeys];
    }
    return keypath;
}

如何处理一对多的关系?
假设,有一个Employee类,有一个属性salary。
控制器中有一个属性emps,数组,包含的是每个Employee类的实例.
控制器中还有一个表示总的salary的属性total。

@interface Employee : NSObject
@property(nonatomic, assign) NSInteger salary;
@end
@interface ViewController ()

@property(nonatomic, copy) NSArray * emps;
@property(nonatomic, strong) NSNumber * total;

@end

    Employee * e1 = [[Employee alloc] init];
    e1.salary = 100;
    Employee * e2 = [[Employee alloc] init];
    e2.salary = 100;
    Employee * e3 = [[Employee alloc] init];
    e3.salary = 100;
    
    [self setValue:@[e1, e2, e3] forKey:@"emps"];
    
    NSIndexSet * set = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.emps.count)];
    
    //这里注册为emps中的每个对象的变化都会发出通知
    [self.emps addObserver:self toObjectsAtIndexes:set forKeyPath:@"salary" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
    
    [self addObserver:self forKeyPath:@"total" options:NSKeyValueObservingOptionNew context:nil];
    
    e3.salary = 300;
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    NSLog(@"change %@", change);
    if ([keyPath isEqualToString:@"salary"]) {
        [self updateTotal];
    } else {
        NSLog(@"---%ld", [self.total integerValue]);
    }
}

- (void)updateTotal {
    //每次salary变化都会重新计算总和
    NSNumber * value = [self valueForKeyPath:@"emps.@sum.salary"];
    [self setValue:value forKey:@"total"];
}
上一篇下一篇

猜你喜欢

热点阅读