1. 概念
KVO,即:Key-Value Observing,键值观察,它提供一种监听属性变化的机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会带上修改前后的值自动通知相应的观察者了。
2. 方法
-
注册观察者
addObserver:forKeyPath:options:context:
-
观察者实现
observeValueForKeyPath:ofObject:change:context:
-
移除观察者
removeObserver:forKeyPath:
3. 验证底层实现
给ViewController类添加3个属性(用于观察)
@interface ViewController : UIViewController
@property (nonatomic, assign) int a;
@property (nonatomic, assign) int b;
@property (nonatomic, assign) int c;
@end
Appdelegate中验证
@implementation AppDelegate
// 获取类的方法列表
+ (NSArray*)classMethodList:(Class)class {
NSMutableArray* array = [NSMutableArray array];
unsigned int count = 0;
Method* methodList = class_copyMethodList(class, &count);
for(int i = 0; i < count; ++i) {
SEL sel = method_getName(*(methodList+i));
[array addObject:NSStringFromSelector(sel)];
}
free(methodList);
return array;
}
// 打印对象的信息
+ (NSString *)logInfo:(id)obj {
NSString* string = [NSString stringWithFormat:@"\t%@\n\t表面的类: %@\n\t真实类型: %@\n\t方法列表: %@\n",
obj,
[obj class],
object_getClass(obj),
[[self classMethodList:object_getClass(obj)] componentsJoinedByString:@" , "]];
return string;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ViewController *vc = [[ViewController alloc] init];
NSLog(@"添加观察者之前:\n%@", [AppDelegate logInfo:vc]);
[vc addObserver:vc forKeyPath:@"a" options:NSKeyValueObservingOptionNew context:nil];
NSLog(@"添加观察者之后:\n%@", [AppDelegate logInfo:vc]);
return YES;
}
@end
打印结果:
2016-10-21 11:10:40.970662 KVO[912:277637] 添加观察者之前:
<ViewController: 0x11be08fc0>
表面的类: ViewController
真实类型: ViewController
方法列表: dealloc , didReceiveMemoryWarning , viewDidLoad , c , setC: , a , b , setA: , setB:
2016-10-21 11:10:40.971306 KVO[912:277637] 添加观察者之后:
<ViewController: 0x11be08fc0>
表面类型: ViewController
真实类型: NSKVONotifying_ViewController
方法列表: setA: , class , dealloc , _isKVOA
Log分析:
- 注册KVO之后, a的表面类型仍然是ViewController, 但是运行时的类型是NSKVONotifying_ViewController, 可见系统在运行时创建了一个ViewController的子类(别问我为什么是子类)NSKVONotifying_ViewController, 将a对象的isa指针指向NSKVONotifying_ViewController.
- 注册KVO后重写了setA:方法, 系统便是在这个方法中带上属性改变前后的值通知观察者.
- 注册KVO后setB:, setC:方法不用重写, 因为并未被观察.
- 注册KVO后重写了class方法, 使他仍然返回ViewController类型, 让改变a对象真实类型显得更加隐蔽.
- 注册KVO后出现 _isKVOA, 猜测这个方法用来标识这是否是一个注册KVO后生成的类.
喜欢的猿友们点个赞哈!!!
网友评论