1.KVO初探学习
2.KVO 底层原理探索
1.KVO初探学习
//先来一个三部曲操作
[self.person addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew) context:"person_name"];
// options是个枚举 NSKeyValueObservingOptionNew
// NSKeyValueObservingOptionOld
// NSKeyValueObservingOptionInitial
// NSKeyValueObservingOptionPrior
// context 参数 是个标签 用来区分 防止多继承的时候会出现问题 并且它的查找更优越(性能高,嵌套少)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.person.name = @"SB";
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"%@ ",change);
}
- (void)dealloc
{
[self.person removeObserver:self forKeyPath:@"name"];
}
移除观察者的重要性 (IOS11之后说不移除是不对的 ),从表象上市看不出来问题的,如果当你使用单例的时候,分别在两个控制器,一个初始化,一个单例,会调用两次,问题很大(必须移除),同时单例也会导致崩溃3
FKDetailViewController :{
kind = 1;
new = "hello word";
}
2019-05-05 18:52:09.932175+0800 001---KVO初探[17802:2935771] {
kind = 1;
new = "hello word";
} -- <FKStudent: 0x600003d49d40>
KVO 也分 手动观察 - 自动观察两种
//自动
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
return YES;
}
// 手动观察需要下面 willChange 和 didChange 方法
- (void)setName:(NSString *)name{
[self willChangeValueForKey:@"name"];
_name = name;
[self didChangeValueForKey:@"name"];
}
集合类型的观察,一定需要通过KVC来,不然是取不到值的
// 取值和赋值过程和普通类型不一样 行不通
// [self.person.dataArray addObject:@"joo"];
// KVC -- 设置值流程 dataArray 是数组
[[self.person mutableArrayValueForKey:@"dataArray"] addObject:@"hello"];
2.KVO 底层原理探索
1.KVO会默认观察setter方法
po object_getClass([self person]) //person 是 FKPerson
NSKVONotifying_FKPerson(动态类) //当前这个对象不再指向原来的person 而是指向了 NSKVONotifying_对象名
不是类的isa 而是当前对象的isa
现在有两个问题
1.NSKVONotifying_FKPerson 是什么时候生成的?
2.NSKVONotifying_FKPerson 和 FKPerson 是什么关系
可以先调用一下下面这个方法
[self printClassAllMethod:[FKPerson class]];
[self printClassAllMethod:NSClassFromString(@"NSKVONotifying_FKPerson")];//如果在一开始没添加KVO时就调用这个类是不存在,会导致崩溃,如果在添加完KVO之后,调用会进行打印
#pragma mark - 遍历类以及子类
- (void)printClasses:(Class)cls{
/// 注册类的总数
int count = objc_getClassList(NULL, 0);
/// 创建一个数组, 其中包含给定对象
NSMutableArray *mArray = [NSMutableArray arrayWithObject:cls];
/// 获取所有已注册的类
Class* classes = (Class*)malloc(sizeof(Class)*count);
objc_getClassList(classes, count);
for (int i = 0; i<count; i++) {
if (cls == class_getSuperclass(classes[i])) {
[mArray addObject:classes[i]];
}
}
free(classes);
NSLog(@"classes = %@", mArray);
}
classes = (
FKPerson,
"NSKVONotifying_FKPerson"
)
这是打印结果, 根据printClasses方法就能知道 NSKVONotifying_FKPerson 是 FKPerson 的子类~~~
KVC动态创建NSKVONotifying_XX类,修改被监听对象isa指针指向,只要调用对象的set方法,
就会调用NSKVONotifying_XX的set方法 (说到底就是对象的set方法有没有调用)
然后说一下他的类方法(methodList)里面发生了那些变化
- (void)printClassAllMethod:(Class)cls{
unsigned int count = 0;
Method *methodList = class_copyMethodList(cls, &count);
for (int i = 0; i<count; i++) {
Method method = methodList[i];
SEL sel = method_getName(method);
IMP imp = class_getMethodImplementation(cls, sel);
NSLog(@"%@-%p",NSStringFromSelector(sel),imp);
}
free(methodList);
}
// 分别调用
[self printClassAllMethod:[FKPerson class]];
[self printClassAllMethod:NSClassFromString(@"NSKVONotifying_FKPerson")];
打印结果
这是FKPerson
2019-05-07 20:00:39.062279+0800 002---KVO原理探讨[32229:4023419] word-0x10e490650
2019-05-07 20:00:39.062457+0800 002---KVO原理探讨[32229:4023419] heelo-0x10e490640
2019-05-07 20:00:39.062564+0800 002---KVO原理探讨[32229:4023419] .cxx_destruct-0x10e490690
2019-05-07 20:00:39.062664+0800 002---KVO原理探讨[32229:4023419] setNickName:-0x10e4905e0
2019-05-07 20:00:39.062759+0800 002---KVO原理探讨[32229:4023419] nickName-0x10e490660
这是NSKVONotifying_FKPerson
2019-05-07 20:00:42.644459+0800 002---KVO原理探讨[32229:4023419] setNickName:-0x10e7ebd1a
2019-05-07 20:00:42.644649+0800 002---KVO原理探讨[32229:4023419] class-0x10e7ea74e
2019-05-07 20:00:42.644830+0800 002---KVO原理探讨[32229:4023419] dealloc-0x10e7ea4f2
2019-05-07 20:00:42.645011+0800 002---KVO原理探讨[32229:4023419] _isKVOA-0x10e7ea4ea
可以看到
1.他重写的setter 方法
2.添加了class
3.析构dealloc
4._isKVOA (KVO标志)
网友评论