一、先看结论,如下:
-
屏蔽内部实现,隐藏了 NSKVONotifying_XXX 类的存在,示例代码如下:
//屏蔽内部实现,隐藏了 NSKVONotifying_XXX 类的存在, XXX 代表原始类的类名 - (Class)class{ return [XXX class]; }
-
重写了属性的 setter 方法,如属性为 age,则示例代码如下:
- (void)setAge:(int)age { __NSSetIntValueAndNotify(); }
-
重写了 dealloc 方法,完成类的收尾工作
-
isKVO 方法,示例代码如下:
- (BOOL)_isKVO { return YES: }
二、为什么是上面这四个方法?猜测添加了KVO 监听的实例对象 isa 指针所指向的类对象中的方法列表都有哪些方法?
- 重写了 setter 方法;
- 重写了 class 方法;
- 重写了 dealloc 方法;
- _isKVO 方法;
尝试证明,代码如下:
- Person 类的代码:
-
Person.h 的代码
#import <Foundation/Foundation.h> @interface Person : NSObject @property (nonatomic,assign) int age; @end
-
Person.m 的代码
#import "Person.h" @implementation Person - (void)willChangeValueForKey:(NSString *)key { [super willChangeValueForKey:key]; NSLog(@"willChangeValueForKey"); } - (void)didChangeValueForKey:(NSString *)key { NSLog(@"didChangeValueForKey - begin"); [super didChangeValueForKey:key]; NSLog(@"didChangeValueForKey - end"); } @end
- ViewController.m 的代码
#import "ViewController.h"
#import <objc/runtime.h>
#import "Person.h"
@interface ViewController ()
@property (nonatomic,strong) Person *person1;
@property (nonatomic,strong) Person *person2;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.person1 = [[Person alloc] init];
self.person1.age = 10;
self.person2 = [[Person alloc] init];
self.person2.age = 20;
//给 person 对象添加 KVO监听
[self.person1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
[self showMethodListOfClass:object_getClass(self.person1)];
[self showMethodListOfClass:object_getClass(self.person2)];
}
//传入一个类对象,并遍历该类对象中的方法列表,并将方法列表打印出来
- (void)showMethodListOfClass:(Class)cls {
NSMutableString *muStr = [NSMutableString string];
unsigned int count;
Method *methodList = class_copyMethodList(cls, &count);
for (unsigned i = 0; i< count; i++) {
Method method = methodList[i];
SEL sel = method_getName(method);
NSString *methodName = NSStringFromSelector(sel);
[muStr appendString:methodName];
[muStr appendString:@", "];
}
NSLog(@"%@",muStr);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.person1.age = 20;
}
//当监听对象对象的属性值发生改变时,就会调用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"监听到 %@ 的 %@ 属性值改变了 -- %@",object,keyPath,change);
}
- (void)dealloc {
[self.person1 removeObserver:self forKeyPath:@"age"];
}
@end
程序运行后,输出结果如下:
setAge:, class, dealloc, _isKVOA,
willChangeValueForKey:, didChangeValueForKey:, age, setAge:,
通过上面的运行结果可以看出,添加了 KVO 监听的实例对象 person1,其 isa 所指象的类对象的方法列表有setAge:, class, dealloc, _isKVOA, 四个方法;而没有添加 KVO 监听的实例对象 person2 其 isa 所指象的类对象的方法列表是 age 属性所生成的 getter 和 setter 方法,同时还有 willChangeValueForKey:, didChangeValueForKey: 的方法。
网友评论