iOS -KVO

作者: CDLOG | 来源:发表于2021-03-11 16:07 被阅读0次

    KVO-键值观察

    KVC:对象取值或者设置值。
    KVO:监听对象值的变化。

    响应式编程的一种。
    KVO的使用非常简单,使用KVO的要求是对象必须能支持kvc机制——所有NSObject的子类都支持这个机制。
    KVO观察的实际是属性的setter方法,成员变量的改变不能被观察到。

    KVO的实现原理如下

    在调用addObserver方法的时候,实现了以下步骤
    1,利用runtime动态创建当前类的子类。
    2,重写子类的setter方法,并在内部回复父类的做法。
    3,动态修改当前类的类型,让他变成子类的类型。(以后调用setter方法,实际是调用子类的setter方法)。

    1,简单的例子,观察person类的name属性的变化

    @interface ViewController ()
    @property (nonatomic, strong) PersonModel * person;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        NSLog(@"load");
        self.person = [[PersonModel alloc]init];
        //添加观察者
        [self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
        
        
    }
    //观察回调
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        NSLog(@"%@",change);
    }
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        static int a = 0;
        self.person.name = [NSString stringWithFormat:@"%d",a++];
    }
    
    //移除观察者
    -(void)dealloc{
        [self.person removeObserver:self forKeyPath:@"name"];
    }
    @end
    
    

    2,手动触发KVO,在需要的时候才触发,默认是自动触发

    在需要手动触发的类重写类方法。
    关闭自动触发

    #import "PersonModel.h"
    
    @implementation PersonModel
    
    //是否自动触发观察key的改变
    +(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
        //name属性手动触发,其他属性自动触发
        if([key isEqualToString:@"name"]){
            return NO;
        }
        return YES;
    }
    
    @end
    
    

    手动触发

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        static int a = 0;
        //即将触发
        [self.person willChangeValueForKey:@"name"];
        self.person.name = [NSString stringWithFormat:@"%d",a++];
        //已经触发
        [self.person didChangeValueForKey:@"name"];
    }
    

    3,类的属性是对象时添加观察的方式。
    person中包含了一个dog对象,观察dog的age。

    //添加观察者
     [self.person addObserver:self forKeyPath:@"dog.age" options:NSKeyValueObservingOptionNew context:nil];
    

    4,数组,字典等容器类,观察不到,因为没有setter方法。但是可以利用KVO观察容器属性的变化
    实际原理是重写了集合的添加方法,删除方法,替换方法,原理和重写setter方法是一样的。

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        //利用KVC获取到arr,注意这里使用的是mutableArrayValueForKey,数组直接初始化数据可以不用KVC。
        NSMutableArray *arr = [self.person mutableArrayValueForKey:@"arr"];
        //KVC可以监听到数组的添加,删除,替换
        [arr addObject:@"11"];
        
        
    }
    

    5,添加一个类的子类的多个属性观察,注意这里子类前要有一个_,也可以直接添加多个观察
    VC.m

    [self.person addObserver:self forKeyPath:@"dog" options:NSKeyValueObservingOptionNew context:nil];
    

    PersonModel.m

    //返回要观察的字符串
    +(NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{
        NSSet *keypath = [NSSet set];
        if([key isEqualToString:@"dog"]){//子类属性名
            keypath = [keypath setByAddingObjectsFromArray:@[@"_dog.name",@"_dog.age"]];
        }
        return keypath;
    }
    

    相关文章

      网友评论

          本文标题:iOS -KVO

          本文链接:https://www.haomeiwen.com/subject/takyqltx.html