iOS KVC

作者: 天空像天空一样蓝 | 来源:发表于2019-09-28 20:54 被阅读0次

KVC

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

1、基础使用

1.1、常用API

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

1.2 使用

创建一个Person类和Cat

@interface Cat : NSObject
@property (assign, nonatomic) int weight;
@end

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

@property (strong, nonatomic) Cat *cat;
@end
  • 使用- (void)setValue:(id)value forKey:(NSString *)key;方法给属性赋值
Person *person = [[Person alloc] init];

[person setValue:@10 forKey:@"age"];
NSLog(@"person的age == %d", person.age);
打印结果:
person的age == 10

上面直接给age属性赋值很简单,但是怎么给Cat类里面的weight属性赋值呢?
直接使用调用[person setValue:@99 forKey:@"cat.weight"]这个方法会报经典的系统错误*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Person 0x10051ed50> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key cat.weight.找不到这个key

  • 使用- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;不仅具有”forKey“的功能,还能给深层次的属性赋值
// Cat 必须初始化一下
person.cat = [[Cat alloc] init];
[person setValue:@99 forKeyPath:@"cat.weight"];
打印结果:
cat的weight == 99
  • 使用- (id)valueForKey:(NSString *)key;获取属性值
[person setValue:@10 forKey:@"age"];
NSLog(@"person的age == %@", [person valueForKey:@"age"]);
打印结果:
person的age == 10
  • 使用- (id)valueForKeyPath:(NSString *)keyPath;获取属性值
person.cat = [[Cat alloc] init];
[person setValue:@99 forKeyPath:@"cat.weight"];
NSLog(@"cat的weight == %@", [person valueForKeyPath:@"cat.weight"]);
打印结果:
cat的weight == 99

2、底层原理

2.1 setValue: forKey:的原理

原理

我们使用 setValue:forKey:的方法给Person类的age属性赋值。

  1. 先去Person类里面找有没有setAge:有的话传递参数,调用改该方法,否则进行第2步
  2. 找到_setAge:方法,有则传递参数,无进行第3步
  3. 找到accessInstanceVariablesDirectly 这个方法,返回一个Bool值
  • 返回为NO表示不允许访问成员变量,调用setValue:forUndefinedKey: 并抛出异常NSUnknownKeyException
  • 返回为YES则可以访问,进行第4步
  1. 会按照_key、_isKey、key、isKey的顺序进行赋值,有则直接赋值,无则进行第5步
  2. 依然会抛出调用setValue:forUndefinedKey: 并抛出异常NSUnknownKeyException这个信息

2.2 valueForKey:的原理

原理
  1. 按照getKey、key、iskey、_key的先后顺序查找方法,如果找到方法直接取值,否则进入第2步
  2. 找到accessInstanceVariablesDirectly 这个方法,返回一个Bool值
  • 返回为NO表示不允许访问成员变量,调用valueForUndefinedKey: 并抛出异常NSUnknownKeyException
  • 返回为YES按照顺序查找成员变量_key、_isKey、key、isKey,如果找到直接取值,否则进入第3步。
  1. 依然会抛出调用valueForUndefinedKey: 并抛出异常NSUnknownKeyException

面试

  • 通过KVC修改属性会触发KVO吗?
    会。
    我们自定义一个Observer MyObserver
#import <Foundation/Foundation.h>
@interface MyObserver : NSObject
@end

#import "MyObserver.h"

@implementation MyObserver

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"observeValueForKeyPath - %@", change);
}

然后调用下面的方法,会发现,打印了上面代码里面的内容

MyObserver *observer = [[MyObserver alloc] init];
MyObserver *person = [[MyObserver 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"];
  • KVC的赋值和取值过程是怎样么?原理是什么
    如 上面2.2的过程

相关文章

网友评论

    本文标题:iOS KVC

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