iOS重学之KVC详解

KCV的基本使用

// 设值
- (void)setValue:(id)value forKey:(NSString *)key;
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;

// 取值
- (id)valueForKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
// Student类
@interface Student : NSObject

@property (nonatomic, copy) NSString *name;

@end

// Person类
@interface Person : NSObject

@property (nonatomic, assign) int age;
@property (nonatomic, strong) Student *student;

@end

// 具体使用
Person *person = [[Person alloc] init];
person.student = [[Student alloc] init];
[person setValue:@(10) forKey:@"age"];
[person setValue:@"Sunny" forKeyPath:@"student.name"];

NSLog(@"age:%@ name:%@", [person valueForKey:@"age"], [person valueForKeyPath:@"student.name"]);

KVC的设值原理

// Person类
@interface Person : NSObject {
  @public
  int _age;
  int _isAge;
  int age;
  int isAge;
}

@end
  
@implementation Person

+ (BOOL)accessInstanceVariablesDirectly {
  return NO;
}

- (void)setAge:(int)age {
  NSLog(@"%s",__func__);
}

- (void)_setAge:(int)age {
  NSLog(@"%s",__func__);
}

- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
  NSLog(@"%s",__func__);
}

@end

// ViewController类
@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  Person *person = [[Person alloc] init];
  [person setValue:@(10) forKey:@"age"];
}

@end

解释
1、当存在setKey方法时,调用setKey
2、当setKey方法不存在,存在_setKey方法时,调用_setKey
3、当setKey_setKey都不存在时,检查+(BOOL)accessInstanceVariablesDirectly返回值。
4、如果+(BOOL)accessInstanceVariablesDirectly返回NO,调用-(void)setValue:(id)value forUndefinedKey:(NSString *)key,程序结束。
5、如果+(BOOL)accessInstanceVariablesDirectly返回YES,按照_key_isKeykeyisKey的顺序查找成员变量赋值。
6、如果按照上面的流程都没找到,调用-(void)setValue:(id)value forUndefinedKey:(NSString *)key,程序结束。

用一张图来总结KVC设值的查找顺序:

1.png

总结
按照上面流程都没有查找到对应的方法或成员变量可以赋值就是调用我们常见的一个方法:- (void)setValue:(id)value forUndefinedKey:(NSString *)key抛出异常。

注意
针对KVC赋值,即使没有找到setKey_setKey,只要找到一个成员变量也是会触发KVO的,KVC本身自己在内部会去通知相应的observer观察者某个属性发生了变化。

其实就是在内部调用了:

- (void)willChangeValueForKey:(NSString *)key;
- (void)didChangeValueForKey:(NSString *)key;

KVC的取值原理

// Person类
@interface Person : NSObject {
  @public
  int _age;
  int _isAge;
  int age;
  int isAge;
}

@end

@implementation Person

+ (BOOL)accessInstanceVariablesDirectly {
  return NO;
}
- (void)getAge {
  NSLog(@"%s",__func__);
}

- (void)age {
  NSLog(@"%s",__func__);
}

- (void)isAge {
  NSLog(@"%s",__func__);
}

- (void)_age {
  NSLog(@"%s",__func__);
}

- (id)valueForUndefinedKey:(NSString *)key {
  NSLog(@"%s",__func__);
}

@end

// ViewController 类
@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  Person *person = [[Person alloc] init];
  [person valueForKey:@"age"];
}

@end

解释
1、当存在getKey方法时,调用getKey
2、当getKey方法不存在,存在key方法时,调用key
3、当getKeykey方法不存在,存在isKey方法时,调用isKey
4、当getKeykeyisKey 方法不存在,存在_key方法时,调用_key
5、当getKeykeyisKey_key都不存在时,检查+(BOOL)accessInstanceVariablesDirectly返回值。
6、如果+(BOOL)accessInstanceVariablesDirectly返回NO,调用- (id)valueForUndefinedKey:(NSString *)key,程序结束。
7、如果+(BOOL)accessInstanceVariablesDirectly返回YES,按照_key_isKeykeyisKey的顺序查找成员变量赋值。
8、如果按照上面的流程都没找到对应的方法或成员变量,调用- (id)valueForUndefinedKey:(NSString *)key,程序结束。

用一张图来总结KVC取值的查找顺序:

2.png

总结
按照上面流程都没有查找到对应的方法或成员变量可以赋值就是调用我们常见的一个方法:- (id)valueForUndefinedKey:(NSString *)key抛出异常。

写在最后

关于iOS里面的KVC设值、取值的相关顺序就写到这里了,如有错误请指教,欢迎去我的个人博客逛逛。

你可能感兴趣的:(iOS重学之KVC详解)