• OC的KVC原理


    KVC

    KVC的全称是Key-Value Coding,俗称"键值编码",可以通过一个key来访问某个属性

    常用的API:

    - (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
    - (void)setValue:(id)value forKey:(NSString *)key;
    - (id)valueForKeyPath:(NSString *)keyPath;
    - (id)valueForKey:(NSString *)key;

    setValue:forKey:原理

    编写如下代码验证

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    @interface LBPerson : NSObject
    {
        int _age;
        int _isAge;
        int age;
        int isAge;
    }
    @property (nonatomic, assign) int age;
    
    @end
    
    @implementation LBPerson
    - (void)_setAge:(int)age {
        _age = age;
        NSLog(@"_setAge");
    }
    - (void)setAge:(int)age {
        _age = age;
        NSLog(@"setAge:");
    }
    
    +(BOOL)accessInstanceVariablesDirectly {
        // 是否允许直接访问属性
        return true;
    }
    
    - (void)willChangeValueForKey:(NSString *)key {
        [super willChangeValueForKey:key];
        NSLog(@"willChangeValueForKey");
        
    }
    
    - (void)didChangeValueForKey:(NSString *)key {
        NSLog(@"didChangeValueForKey Start");
        [super didChangeValueForKey:key];
        NSLog(@"didChangeValueForKey End");
    }
    @end
    
    @interface ViewController ()
    @property (nonatomic, strong) LBPerson *person;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        LBPerson *person = [[LBPerson alloc] init];
        self.person = person;
        LBPerson *person1 = [[LBPerson alloc] init];
        [person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:@"test"];
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        [self.person setValue:@20 forKey:@"age"];
    }
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        NSLog(@"监听到%@的%@属性值改变了 - %@ - %@", object, keyPath, change, context);
    }
    
    - (void)dealloc {
        [self.person removeObserver:self forKeyPath:@"age"];
    }

    从上述代码的打印结果,可以验证setValur:forKey:,会顺序调用setKey、_setKey,如果没找到方法,会调用accessInstanceVariablesDirectly。如果该方法返回的是true,会按照优先级给属性赋值age、isAge、_age、_isAge。如果还没有找到,就会报错。调用结果如下图所示:

    通过打印也验证了,setValue:forKey:也会触发KVO

    valueForKey:原理

    - (int)getAge
    {
        return 1;
    }
    
    - (int)age
    {
        return 2;
    }
    
    - (int)isAge
    {
        return 3;
    }
    
    - (int)_age
    {
        return 4;
    }

    通过打印可验证,valueForKey的调用顺序getAge、age、isAage、_age

  • 相关阅读:
    python运维之saltstack方式
    windows下使用vim
    django-redis中文文档
    Skipping GMP tests ([WinError 126] 找找不不到到指指定定的的模模块块。。)
    python pycryptodome库,及后台支付宝功能接入
    关于python时间相关的函数记录集合
    mysql练习题博客集
    mysql -uroot -p -P3306 -h192.168.0.111无法远程连接mysql
    报错 Storing debug log for failure in /root/.pip/pip.log
    多进程 库multiprocessing
  • 原文地址:https://www.cnblogs.com/muzichenyu/p/14027981.html
Copyright © 2020-2023  润新知