現在有一個Person
對象
@interface Person : NSObject
@property (copy, nonatomic) NSString *name;
@end
通過KVO或者RAC對其監聽后,分別執行下面的代碼
- 外面設置
name
// 1
_person.name = @"Jack";
// 2
[_person setValue:@"Jack" forKey:@"name"];
// 3
[_person setValue:@"Jack" forKey:@"_name"];
- 內部設置
name
// 4
self.name = @"Jack";
// 5
_name = @"Jack";
// 6
[self setValue:@"Jack" forKey:@"name"];
// 7
[self setValue:@"Jack" 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, @"Jack");
}
}
結果: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
方法,所以無法觸發監聽。
我們在使用KVC時,key
加不加_
決定了是否走setter
方法。
RAC的監聽機制應該也是和KVO一樣,所以如果是使用3的方法設置是不會觸發監聽的。
拓展:如何監聽數組的變化?
正常KVO/RAC監聽數組時,即使我們修改了數組的內容(這里指修改數組內部的內容-增刪改)因為沒有觸發setter
方法所以不會觸發監聽,最簡單的就是加一句self.arr = self.arr
就可以觸發監聽了。