标签:
1、在父类中注册KVO 子类中KVO不相应的解决办法 在父类中通过判断发送对象的类是不是父类或者子类
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { //区分子类和父类KVO 简单判断 if (object == self) { if ([keyPath isEqualToString:@"x"]) { NSObject *new = [change objectForKey:@"new"]; NSLog(@"new x is %@",new); } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } else {
//调用子类 [object observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } }
2、不要盲目的removeObserver,特别是父类和子类中同时存在KVO 因为容易出现二次removeObserver 导致程序崩溃。
3、KVO底层的实现原理
@interface ClassTest : NSObject { int x; int y; int z; } @property (nonatomic, assign) int x; @property (nonatomic, assign) int y; @property (nonatomic, assign) int z; @end @implementation ClassTest @synthesize x, y,z; -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if([keyPath isEqualToString:@"x"]) { NSObject* new = [change objectForKey:@"new"]; NSLog(@"new x is %@", new); } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } @end
//获取方法列表
static NSArray* classMethodList(Class c) { NSMutableArray* array = [NSMutableArray arrayWithCapacity:5]; unsigned int count = 0; Method* methodList = class_copyMethodList(c, &count); for(int i = 0; i < count; ++i) { SEL sel = method_getName(*(methodList+i)); [array addObject:NSStringFromSelector(sel)]; } free(methodList); return array; }
static void printDescription(NSString* name, id obj) { NSString* string = [NSString stringWithFormat:@"%@:%@\n\tclass %@\n\tobjclass %@\n\timplementmethod %@\n", name, obj, [obj class], object_getClass(obj), [classMethodList(object_getClass(obj)) componentsJoinedByString:@" , "]]; printf("%s", [string UTF8String]); }
ClassTest* x = [[ClassTest alloc] init]; ClassTest* y = [[ClassTest alloc] init]; ClassTest* xy = [[ClassTest alloc] init]; ClassTest* control = [[ClassTest alloc] init]; [x addObserver:x forKeyPath:@"x" options:NSKeyValueObservingOptionNew context:nil]; [y addObserver:y forKeyPath:@"y" options:NSKeyValueObservingOptionNew context:nil]; [xy addObserver:xy forKeyPath:@"x" options:NSKeyValueObservingOptionNew context:nil]; [xy addObserver:xy forKeyPath:@"y" options:NSKeyValueObservingOptionNew context:nil]; printDescription(@"x", x); printDescription(@"y", y); printDescription(@"xy", xy); printDescription(@"control", control); printf("Using NSObject method, normal setX is %p, overrite setX is %p\n", [control methodForSelector:@selector(setX:)], [x methodForSelector:@selector(setX:)]); printf("Using libobjc method, normal setX is %p, overrite setX is %p\n", class_getMethodImplementation(object_getClass(control), @selector(setX:)), class_getMethodImplementation(object_getClass(x), @selector(setX:)));
输出结果:
x:<ClassTest: 0x8951690> class ClassTest objclass NSKVONotifying_ClassTest implementmethod setY: , setX: , class , dealloc , _isKVOA y:<ClassTest: 0x89516c0> class ClassTest objclass NSKVONotifying_ClassTest implementmethod setY: , setX: , class , dealloc , _isKVOA xy:<ClassTest: 0x89516d0> class ClassTest objclass NSKVONotifying_ClassTest implementmethod setY: , setX: , class , dealloc , _isKVOA control:<ClassTest: 0x89516e0> class ClassTest objclass ClassTest implementmethod z , x , setX: , y , setY: , setZ: , observeValueForKeyPath:ofObject:change:context: Using NSObject method, normal setX is 0x4ae0, overrite setX is 0x1134526 Using libobjc method, normal setX is 0x4ae0, overrite setX is 0x1134526
实际上系统定了一个叫做 NSKVONotifying_ClassTest的子类,子类中实现了
setY: , setX: , class , dealloc , _isKVOA函数,这个_isKVOA函数应该是个私有函数,用来判断是否kvo框架生成的类,x, y, xy对象的运行时类都指向NSKVONotifying_ClassTest,通过class函数返回的类还是指向ClassTest,但是control对象的不管运行时类还是class函数返回的类都指向ClassTest。这样就验证了系统是通过定义Classtest类的子类来实现属性方法发送通知的,系统很聪明,子类中并没有实现setZ方法,因为我们并没有对属性z添加观察者。
在看看最后两行打印的结果,control对象的setX函数地址和x对象的setX函数地址是不一样的,说明setX函数被重写了。看别人之前的文章,通过NSObject方法打印control和x的setX函数地址是一样的,现在验证的结果地址却不一样,和使用runtime方法打印的结果完全一致,这个估计是新的系统底层做了修改,让使用NSObject的methodForSelector方法获得函数是子类的函数。
标签:
原文地址:http://www.cnblogs.com/wydoublefish/p/4484080.html