假设有一个类LGLCoder
,有一个属性 lglName
@interface LGLCoder : NSObject
@property (nonatomic, strong) NSString * lglName;
@end
系统动态创建了一个子类NSKVONotifying_ LGLCoder
LGLCoder 的实例对象的 isa 地址指向NSKVONotifying_ LGLCoder
LGLCoder * lglCode = [[LGLCoder alloc] init];
NSLog(@"KVO之前 == %p --- %@", object_getClass(lglCode), object_getClass(lglCode));
[lglCode addObserver:self forKeyPath:@"lglName" options:NSKeyValueObservingOptionNew context:nil];
NSLog(@"KVO之后 == %p ---- %@", object_getClass(lglCode), object_getClass(lglCode));
运行结果
KVO之前 == 0x10fe17638 --- LGLCoder
KVO之后 == 0x600003f1de60 ---- NSKVONotifying_LGLCoder
重写了lglName属性的四个方法(setLglName 、class、 dealloc 、 _isKVOA)
通过输出监听以后类的对象的所有方法
///查看对象方法
- (void)lgl_methodNamesOfClass:(Class)cls {
unsigned int count;
Method *methodList = class_copyMethodList(cls, &count);
for (int i = 0; i < count; i++) {
Method method = methodList[i];
SEL selector = method_getName(method);
NSLog(@"%@",NSStringFromSelector(selector));
}
free(methodList);
}
///开启监听
[lglCode addObserver:self forKeyPath:@"lglName" options:NSKeyValueObservingOptionNew context:nil];
NSLog(@"--------------------------------");
NSLog(@"KVO之后 == %p ---- %@", object_getClass(lglCode), object_getClass(lglCode))
[self lgl_methodNamesOfClass:object_getClass(lglCode)];
运行结果
KVO之后 == 0x6000030d8630 ---- NSKVONotifying_LGLCoder
setLglName
class
dealloc
_isKVOA
手动触发 KVO
在设置 lglName 属性时:
willChangeValueForKey、didChangeValueForKey会依次被调用。
监听的动作是在didChangeValueForKey中被触发的
#import "LGLCoder.h"
@implementation LGLCoder
- (void)setLglName:(NSString *)lglName {
NSLog(@"开始调用赋值:lglName = %@",lglName);
_lglName = lglName;
}
- (void)willChangeValueForKey:(NSString *)key {
NSLog(@"开始调用 -- willChangeValueForKey");
[super willChangeValueForKey:key];
NSLog(@"结束调用 -- willChangeValueForKey");
}
- (void)didChangeValueForKey:(NSString *)key {
NSLog(@"开始调用 -- didChangeValueForKey");
[super didChangeValueForKey:key];
NSLog(@"结束调用 -- didChangeValueForKey");
}
@end
设置监听和赋值
LGLCoder * lglCode = [[LGLCoder alloc] init];
///开启监听
[lglCode addObserver:self forKeyPath:@"lglName" options:NSKeyValueObservingOptionNew context:nil];
lglCode.lglName = @"lgl";
实现监听结果回调
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"监听到结果改变:%@--%@--%@",keyPath,object,change);
}
运行结果
开始调用 -- willChangeValueForKey
结束调用 -- willChangeValueForKey
开始调用赋值:lglName = lgl
开始调用 -- didChangeValueForKey
监听到结果改变:lglName--<LGLCoder: 0x60000306e670>--{
kind = 1;
new = lgl;
}
结束调用 -- didChangeValueForKey
根据上面的运行结果发现,我们可以通过willChangeValueForKey 、didChangeValueForKey
来手动触发 KVO。
LGLCoder * lglCode = [[LGLCoder alloc] init];
///开启监听
[lglCode addObserver:self forKeyPath:@"lglName" options:NSKeyValueObservingOptionNew context:nil];
[lglCode willChangeValueForKey:@"lglName"];
[lglCode didChangeValueForKey:@"lglName"];
运行结果
开始调用 -- willChangeValueForKey
结束调用 -- willChangeValueForKey
开始调用 -- didChangeValueForKey
监听到结果改变:lglName--<LGLCoder: 0x600000fa0590>--{
kind = 1;
new = "<null>";
}
结束调用 -- didChangeValueForKey
这里因为我们没有给lglName
赋值(所以new = "<null>";)
,系统也调用了-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
方法。这样就达到了我们手动触发的目的
网友评论