• 01-02 iOS kvo、kvc


    #import "ViewController.h"
    #import "FQPeople.h"
    @interface ViewController ()
    
    @property(nonatomic,strong) FQPeople *people;
    @property(nonatomic,strong) FQPeople *people1;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.people = [FQPeople new];
        self.people1 = [FQPeople new];
        self.people1.age = 20;
        self.people.age = 20;
        [self.people addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        NSLog(@"%@",@"这里被执行了");
        self.people.age = 21;
        [self.people1 setAge:22];
    }
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        if ([keyPath isEqualToString: @"age"] && object == self.people) {
            NSLog(@"%@",change);
        }
    }
    
    - (void)dealloc{
        [self removeObserver:self forKeyPath:@"age"];
    }
    

    1.1、引入

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        self.people.age = 21;
        [self.people1 setAge:22];
    }
    

    这两个方法都调用了People类的setAge方法。为什么people监听会被调用,people1不会呢?

    setter方法是一样的,那就是people对象有不一样的地方, 接着往下看

    1.2、isa的指向

    不使用kvo (没有注册监听的时候)poeple 的isa指针指向的原来的类,即:WQPeople

    使用kvo

    在runtime创建了一个MJPerson的子类新类NSKVONotifying_MJPerson,并把poeple对象的isa指针指向 NSKVONotifying_MJPerson的类对象,

    self.p1 = [[People alloc] init];
    self.p2 = [[People alloc] init];
        
    [self.p1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    
    NSLog(@"%@",object_getClass(self.p1));//NSKVONotifying_People
    NSLog(@"%@",object_getClass(object_getClass(self.p1)));//People
    NSLog(@"%@",object_getClass(object_getClass(object_getClass(self.p1))));//NSObject
    
    
    NSLog(@"%@",object_getClass(self.p2));//People
    NSLog(@"%@",object_getClass(object_getClass(self.p2)));//People
    NSLog(@"%@",object_getClass(object_getClass(object_getClass(self.p2))));//People
    
    

    1.3、方法的调用流程

    没有使用kvo:

    self.p1 = [[People alloc] init];
    self.p2 = [[People alloc] init];
        
    [self.p1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    

    p2,没有使用kvo,没有产生新的类,直接使用p2的isa指针找到p2的类对象,底层是objc_sendMsg() 这个流程访问原来的People中的setAge

    使用了kvo runtime产生了新的类,

    先p1的isa 找到People的类对象 找到NSKVONotifying_FQPeople 的setAge 在调用这个setAge时,调用的是fundation框架的 _NSSetIntValueAndNotify()

    _这个_NSSetXXXValueAndNotify() 执行

    • willChangeValueForKey

    • 父类原来的setter进行真正的赋值

    • didChangeValueForKey;

      这里面会触发observe监听器的observeValueForKeyPath:ofObject:change方法。

    那么setAge 和NSSetXXXValueAndNotify怎么关联的呢?

    执行setAge时它的方法指针(IMP)直接指向了NSSetXXXValueAndNotify

     [self.p1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    
    ///获取imp
    [self.p1 methodForSelector:@selector(setAge:)];
    

    大概实现是

    2 通过kvc获取值的过程,原理是什么?

  • 相关阅读:
    C#计算某一些任务的执行时间(消耗时间)
    C#打印条码的几种方式
    使用escape编码地址栏中的中文字符
    SQL 批量删除数据表
    弹出层并锁定页面
    后台输出HTML
    C# 十进制与十六进制互转
    SQL判断临时表是否存在
    SQL Server 字符串处理
    Vue文件跳转$router传参数
  • 原文地址:https://www.cnblogs.com/xiaowuqing/p/14027584.html
Copyright © 2020-2023  润新知