KVO

作者: AntKing | 来源:发表于2019-04-10 09:37 被阅读0次

    先来定义一个类,要被我们监听的类

    • YSPerson.h 文件
    
    #import <Foundation/Foundation.h>
    
    @interface YSPerson : NSObject
    @property (assign, nonatomic) int age;
    @end
    
    
    • YSPerson.m文件
    
    @implementation YSPerson
    {
        int _age;
    }
    
    - (void)setAge:(int)age
    {
        _age = age;
    }
    
    - (int)age
    {
        return _age;
    }
    
    @end
    
    

    在控制器中监听YSPerson 实例对象的 age

    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.person1 = [[YSPerson alloc] init];
        self.person1.age = 1;
        
        NSLog(@"person1添加KVO监听之前 - %@",
              object_getClass(self.person1));
        NSLog(@"person1添加KVO监听之前 - %p",
              [self.person1 methodForSelector:@selector(setAge:)]);
    
        // 给person1对象添加KVO监听
        NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
        [self.person1 addObserver:self forKeyPath:@"age" options:options context:@"123"];
    
        NSLog(@"person1添加KVO监听之后 - %@",
              object_getClass(self.person1));
        NSLog(@"person1添加KVO监听之后 - %p ",
              [self.person1 methodForSelector:@selector(setAge:)]);
    
    
      /*
      通过上面的打印输出,可以证明,监听前后的实例对象的类型和
      setAge的方法地址都是不一样的,验证了我们的猜想
    */
    
    }
    
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
    //    self.person1.age = 21;
    
        // NSKVONotifying_YSPerson是使用Runtime动态创建的一个类,是YSPerson的子类
        // self.person1.isa == NSKVONotifying_YSPerson
        [self.person1 setAge:21];
        
    }
    
    
    - (void)dealloc {
        [self.person1 removeObserver:self forKeyPath:@"age"];
    }
    
    // 当监听对象的属性值发生改变时,就会调用
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
    {
        NSLog(@"监听到%@的%@属性值改变了 - %@ - %@", object, keyPath, change, context);
    }
    
    
    • 当我们点击屏幕的时候,给self.person1的age赋值 21时候,我们就能监听到值的改变

    • 实现原理是利用Runtime来完成

    • 当我们监听了YSPerson的属性的时候,系统会在Runtime阶段为我们创建一个NSKVONotifying_YSPerson ,这个类继承自YSPerson

    • 在NSKVONotifying_YSPerson的实现中插入了以下代码

    @implementation NSKVONotifying_YSPerson
    
    - (void)setAge:(int)age
    {
        _NSSetIntValueAndNotify();
    }
    
    // 伪代码
    void _NSSetIntValueAndNotify()
    {
        [self willChangeValueForKey:@"age"];
        [super setAge:age];
        [self didChangeValueForKey:@"age"];
    }
    
    - (void)didChangeValueForKey:(NSString *)key
    {
        // 通知监听器,某某属性值发生了改变
        [oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
    }
    
    @end
    
    
    
    • 并将NSKVONotifying_YSPerson的 class 方法,所以在我们调用[self.person1 class] 方法的时候返回的还是YSPerson

    相关文章

      网友评论

          本文标题:KVO

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