iOS-底层原理(5)-KVC底层原理详解

面试题
1. 通过KVC修改属性会触发KVO么?
  • 会触发KVO

代码例子佐证

@interface Person : NSObject
@property (assign, nonatomic) int age;
@end

@interface Observer : NSObject
@end
@implementation Observer
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    NSLog(@"observeValueForKeyPath - %@", change);
}
@end

#import 
#import "Person.h"
#import "Observer.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Observer *observer = [[Observer alloc] init];
        Person *person = [[Person alloc] init];
        
        // 添加KVO监听
        [person addObserver:observer forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
        
        // 通过KVC修改age属性
        [person setValue:@10 forKey:@"age"];
        
        // 移除KVO监听
        [person removeObserver:observer forKeyPath:@"age"];
    }
    return 0;
}

运行结果

iOS-底层原理(5)-KVC底层原理详解_第1张图片
KVC.png
2. KVC的赋值和取值过程是怎样的?原理是什么?
  • 详情见下文的valueForKey:的原理图
序言

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:的原理
iOS-底层原理(5)-KVC底层原理详解_第2张图片
image.png

代码例子佐证

  • accessInstanceVariablesDirectly返回NO
// 默认的返回值就是YES
+ (BOOL)accessInstanceVariablesDirectly {
    return NO;
}
iOS-底层原理(5)-KVC底层原理详解_第3张图片
image.png
  • accessInstanceVariablesDirectly返回YES,并且有下划线成员变量
@interface Person : NSObject {
@public
    int age;
    int isAge;
    int _isAge;
    int _age;
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Person *person = [[Person alloc] init];
        // 通过KVC修改age属性
        [person setValue:@10 forKey:@"age"];
        
        NSLog(@"%@", [person valueForKey:@"age"]);
    }
    return 0;
}

运行结果

iOS-底层原理(5)-KVC底层原理详解_第4张图片
image.png

可以将变量依次注释,看看打印结果ageisAge_isAge_age

@public
    int age;
    int isAge;
//    int _isAge;
//    int _age;
}

运行结果

iOS-底层原理(5)-KVC底层原理详解_第5张图片
image.png
valueForKey:的原理
iOS-底层原理(5)-KVC底层原理详解_第6张图片
valueForKey.png
  • 代码例子佐证 - 先找方法
@implementation Person

// 第一顺序调用
- (int)getAge {
    return 11;
}

// 第二顺序调用
- (int)age {
    return 12;
}

// 第三顺序调用
- (int)isAge {
    return 13;
}

// 第四顺序调用
- (int)_age {
    return 14;
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Person *person = [[Person alloc] init];

        NSLog(@"%@", [person valueForKey:@"age"]);
    }
    return 0;
}
  • 依次注释掉方法getAgeageisAge_age,然后打印结果如下
getAge.png
age.png
isAge.png
_age.png
  • 代码例子佐证 - 再找成员变量
@interface Person : NSObject {
@public
    int age;
    int isAge;
    int _isAge;
    int _age;
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Person *person = [[Person alloc] init];
        // 通过KVC修改age属性
        person->_age = 100;
        person->_isAge = 110;
        person->age = 120;
        person->isAge = 130;
        
        NSLog(@"%@", [person valueForKey:@"age"]);
    }
    return 0;
}
  • 依次在Person.h文件中注释成员变量_age_isAgeageisAge,然后查看打印结果
_age.png
_isAge.png
age.png
isAge.png

如果将方法和成员变量全部去掉,打印结果如下

iOS-底层原理(5)-KVC底层原理详解_第7张图片
image.png

由打印结果可知,如果方法和成员变量都找不到,则最终方法找不到的错误。


本文参考借鉴MJ的教程视频,非常感谢.


项目连接地址 - iOS-KVC

你可能感兴趣的:(iOS-底层原理(5)-KVC底层原理详解)