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

posted @ 2020-11-23 23:33  木子沉雨  阅读(181)  评论(0编辑  收藏  举报