现在有一个XGPerson
对象
@interface XGPerson : NSObject
@property (copy, nonatomic) NSString *name;
@end
通过KVO对XGPerson的name属性监听以后,分别执行下面的代码
- 外面设置
name
// 1
_person.name = @"程序员学哥";
// 2
[_person setValue:@"程序员学哥" forKey:@"name"];
// 3
[_person setValue:@"程序员学哥" forKey:@"_name"];
- 内部设置
name
// 4
self.name = @"程序员学哥";
// 5
_name = @"程序员学哥";
// 6
[self setValue:@"程序员学哥" forKey:@"name"];
// 7
[self setValue:@"程序员学哥" forKey:@"_name"];
- runtime设置
name
unsigned int outCount = 0;
Ivar *ivars = class_copyIvarList([Person class], &outCount);
for (int i = 0; i < outCount; i++) {
Ivar ivar = ivars[i];
if ([[NSString stringWithUTF8String:ivar_getName(ivar)] isEqualToString:@"_name"]) {
// 8
object_setIvar(_person, ivar, @"程序员学哥");
}
}
结果:1、2、4、6会触发监听,而3、5、7、8不会触发。
原因:KVO的本质是通过isa-swizzling
新建了一个子类,并且重写了属性的setter
方法,在setter
方法的头和尾分别执行了willChangeValueForKey:
和didChangevlueForKey:
两个方法来实现监听的。
因为1、2、4、6会走setter
方法,而3、5、7、8直接设置name
属性,并没有走setter
方法,所以无法触发监听。
拓展
1:KVC 触发KVO
我们在使用KVC时,key
加不加_
决定了是否走setter
方法。
2:KVO监听数组的变化
正常KVO监听数组时,即使我们修改了数组的内容(这里指修改数组内部的内容-增删改)因为没有触发setter
方法所以不会触发监听,最简单的就是加一句self.arr = self.arr
就可以触发监听了。