iOS开发基础.png
KVC实现了基于KEY访问对象属性的一套查找规则,可以直接操作对象的属性,变量即使设置为私有的也一样访问。
要操作一个对象首先要把它找出来,KVC底层机制实现了其一步步的查找规则。了解它的处理机制更有利于设计我们的类,方法实现等操作。
通过valueForKey:
方法获取值
get<Key>, <key>, is<Key>, or _<key>
的方法。如果找到了就返回 -> 第5步,找不到继续下一步。countOf<Key>
, objectIn<Key>AtIndex:
, <key>AtIndexes:
方法//必须实现
countOf<Key>
//必须实现其中一个
objectIn<Key>AtIndex:
<key>AtIndexes:
如果存在,创建一个集合代理对象,这个对象就像和NSArray
一样来使用,返回该对象。否则下一步。
countOf<Key>,
enumeratorOf<Key>,
and memberOf<Key>:
如果存在,创建一个集合代理对象,就像和NSSet
一样来使用,返回该对象。否则下一步。
判断是否可以直接访问实例变量,
+ (BOOL)accessInstanceVariablesDirectly
如果返回true,按照以下顺序查找:
_<key>, _is<Key>, <key>, is<Key>
找到了执行第5步 , 没找到执行第6步。
NSNumber
支持的数值类型,包装成NSNumber
对象,返回。
如果不是NSNumber
支持的数值类型,包装成NSValue
对象,返回。valueForUndefinedKey:
抛出异常
我们可重写该方法实现,至此整个查找流程结束。通过setValue:forKey:
方法设置操作
判断是否可以直接访问实例变量,
+ (BOOL)accessInstanceVariablesDirectly
如果返回true,按照以下顺序查找:
_<key>, _is<Key>, <key>, is<Key>
如果找到指定变量名的实例变量直接赋值然后完成返回。否则下一步3
setValue:forUndefinedKey:
抛出异常。数组的查找方法为
mutableArrayValueForKey:
,其查找过程类似。
//////集合操作
NSArray * arr = @[@10 , @13 , @5 , @20 , @30];
NSInteger count = [[arr valueForKeyPath:@"@count"] integerValue];
NSLog(@"count:%ld" , (long)count);
NSInteger min = [[arr valueForKeyPath:@"@min.integerValue"] integerValue];
NSLog(@"min:%ld" , (long)min);
NSInteger max = [[arr valueForKeyPath:@"@max.integerValue"] integerValue];
NSLog(@"max:%ld" , (long)max);
NSInteger sum = [[arr valueForKeyPath:@"@sum.integerValue"] integerValue];
NSLog(@"sum:%ld" , (long)sum);
NSInteger avg = [[arr valueForKeyPath:@"@avg.integerValue"] integerValue];
NSLog(@"avg:%ld" , (long)avg);
子类的get方法->父类的get方法->accessInstanceVariablesDirectly是否返回YES-->子类的成员变量>父类的成员变量。此外还支持路径查询。
KVC优缺点:
优点:可以根据对象属性名直接访问,不管是否设置为私有都可取到。
缺点:解析key字符串,一步步的查找难免不费时间。
KVO是观察者模式的一个实现,利用runtime的机制,当对一个对象进行观察时,会在运行时创建一个该对象的子类,这个子类一般以NSKVONotifying_xxx(xxx为父类的名字)命名,子类中会重写所有被观察属性的set方法,除了创建子类,还会将该对象的isa指针指向这个子类,当被观察的对象属性修改时,通过isa找到子类,在通过子类的方法列表找到对应的set方法,set方法是被重写过得,里面实现了相关的通知。
引用网络一个图说明其流程:
kvo实现原理.png
//官方demo
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
BOOL automatic = NO;
if ([theKey isEqualToString:@"balance"]) {
automatic = NO;
}
else {
automatic = [super automaticallyNotifiesObserversForKey:theKey];
}
return automatic;
}
修改setter方法:
- (void)setBalance:(double)theBalance {
[self willChangeValueForKey:@"balance"];
_balance = theBalance;
[self didChangeValueForKey:@"balance"];
}
//一次修改多个值
- (void)setBalance:(double)theBalance {
[self willChangeValueForKey:@"balance"];
[self willChangeValueForKey:@"itemChanged"];
_balance = theBalance;
_itemChanged = _itemChanged+1;
[self didChangeValueForKey:@"itemChanged"];
[self didChangeValueForKey:@"balance"];
}
willChangeValueForKey:告诉观察者值将要改变; didChangeValueForKey:告诉观察者值已经改变;这两个方法必须成对出现。
KVO优缺点:
优点:
缺点:
Key-Value Coding Programming Guide Key-Value Observing Programming Guide 好好看看 KVC && KVO-https://juejin.im/post/5c52acabe51d4551c75ffa5b