MHFPerson.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface MHFPerson : NSObject
{
@public
int _no;
}
@property (assign, nonatomic)int age;
@end
NS_ASSUME_NONNULL_END
MHFPerson.m
#import "MHFPerson.h"
@implementation MHFPerson
- (void)setAge:(int)age
{
_age = age;
NSLog(@"调用setAge:方法");
}
- (void)willChangeValueForKey:(NSString *)key
{
[super willChangeValueForKey:key];
NSLog(@"willChangValueForKey");
}
- (void)didChangeValueForKey:(NSString *)key
{
NSLog(@"didChangeValueForKey - begin");
[super didChangeValueForKey:key];
NSLog(@"didChangeValueForKey - end");
}
@end
伪代码NSKVONotifying_MHFPerson.h
#import "MHFPerson.h"
NS_ASSUME_NONNULL_BEGIN
@interface NSKVONotifying_MHFPerson : MHFPerson
@end
NS_ASSUME_NONNULL_END
伪代码NSKVONotifying_MHFPerson.m
#import "NSKVONotifying_MHFPerson.h"
@implementation NSKVONotifying_MHFPerson
/*
- (void)setAge:(int)age
{
_NSSetIntValueAndNotify();
}
// 伪代码
void _NSSetIntValueAndNotify()
{
[self willChangeValueForKey:@"age"];
[super setAge:age];// 调用原来的setter方法实现
[self didChangeValueForKey:@"age"];
}
- (void)didChangeValueForKey:(NSString *)key
{
// 通知监听器,某某属性值发生了改变
[observe observeValueForKeyPath:key ofObject:self change:nil context:nil];
}
*/
// 屏蔽内部实现,隐藏NSKVONotifying_MHFPerson类的存在
-(Class)class
{
}
- (void)dealloc
{
// 收尾工作
}
- (BOOL)_isKVOA
{
return YES;
}
@end
ViewController.m
#import "ViewController.h"
#import "MHFPerson.h"
#import <objc/runtime.h>
@interface ViewController ()
@property (strong, nonatomic)MHFPerson *personFirst;
@property (strong, nonatomic)MHFPerson *personSecond;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.personFirst = [[MHFPerson alloc]init];
// self.personFirst.age = 10;
self.personFirst->_no = 0;
self.personSecond = [[MHFPerson alloc]init];
self.personSecond.age = 11;
NSLog(@"personFirst添加KVO监听之前 - %@ %@ \n methodForSelector:%p - %p\n",object_getClass(self.personFirst),object_getClass(self.personSecond),[self.personFirst methodForSelector:@selector(setAge:)],[self.personSecond methodForSelector:@selector(setAge:)]);
// 给personFirst对象添加KVO监听
[self.personFirst addObserver:self forKeyPath:@"no" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
NSLog(@"personFirst添加KVO监听之后 - %@ %@\n methodForSelector:%p - %p",object_getClass(self.personFirst),object_getClass(self.personSecond),[self.personFirst methodForSelector:@selector(setAge:)],[self.personSecond methodForSelector:@selector(setAge:)]);
// NSLog(@"类对象 - %@ %@",object_getClass(self.personFirst),object_getClass(self.personSecond));
// NSLog(@"元类对象 - %@ %@",object_getClass(object_getClass(self.personFirst)),object_getClass(object_getClass(self.personSecond)));
/*
2019-03-05 15:22:40.993133+0800 OCEssence[23720:297744] 类对象 - NSKVONotifying_MHFPerson MHFPerson
2019-03-05 15:22:43.886798+0800 OCEssence[23720:297744] 元类对象 - NSKVONotifying_MHFPerson MHFPerson
*/
NSLog(@"类对象 - %@ %@",object_getClass(self.personFirst),object_getClass(self.personSecond));
NSLog(@"类对象 - %@ %@",[self.personFirst class],[self.personSecond class]);
[self printMethodNamesOfClass:object_getClass(self.personFirst)];
[self printMethodNamesOfClass:object_getClass(self.personSecond)];
}
- (void)printMethodNamesOfClass:(Class)cls
{
NSMutableArray *methodNameArray = [NSMutableArray array];
unsigned int count;
// 获得方法数组
Method *methodList = class_copyMethodList(cls, &count);
for (int i = 0; i < count; i++) {
Method first = methodList[i];
NSString *methodName = NSStringFromSelector(method_getName(first));
[methodNameArray addObject:methodName];
}
free(methodList);
NSLog(@"%@",methodNameArray);
//MHFPerson类中的方法有四个 @"setAge:",@"class",@"dealloc",@"_isKVOA"
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// [self.personFirst setAge:20];
// [self.personSecond setAge:21];
[self.personFirst willChangeValueForKey:@"no"];
self.personFirst->_no = 10;
[self.personFirst didChangeValueForKey:@"no"];
/*
(lldb) p self.personFirst.isa
(Class) $1 = NSKVONotifying_MHFPerson
(lldb) p self.personSecond.isa
(Class) $2 = MHFPerson
*/
// self.personFirst.isa = NSKVONotifying_MHFPerson
// self.personSecond.isa = MHFPerson
// 实例对象的isa指向的是class类对象,说明personFirst这个类对象指向的是NSKVONotifying_MHFPerson这个类,而personSecond的类对象指向的是MHFPerson这个类,说明如果一个对象添加了KVO说明它的类对象不是以前指向的类对象,这个是Runtime在程序运行过程中动态创建的一个新的类NSKVONotifying_MHFPerson,这个是MHFPerson的一个子类
/*
personFirst添加KVO监听之后 - NSKVONotifying_MHFPerson MHFPerson
methodForSelector:0x1023c0fc2 - 0x102065200
(lldb) p (IMP)0x1023c0fc2
(IMP) $0 = 0x00000001023c0fc2 (Foundation`_NSSetIntValueAndNotify)
(lldb) p (IMP)0x102065200
(IMP) $1 = 0x0000000102065200 (OCEssence`-[MHFPerson setAge:] at MHFPerson.m:12)
*/
}
- (void)dealloc
{
[self.personFirst removeObserver:self forKeyPath:@"age"];
}
//
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"监听到%@的%@属性值改变了 %@",object,keyPath,change);
}
@end