iOS KVO 实现分析

KVO提供了一种方法,当某个属性改变时,相应的对象会被通知。

概述

1、通过runtime实现,当观察某个对象时,runtime会创建一个新的子对象。在这个新对象中,它重写了所有被观察的key,然后将object的isa指向新class(这个指针告诉OC运行时某个对象到底是哪种类型的对象)。因此这个添加观察者的对象就无声无息间变成了新的子类的实例。

2、当出发setKey方法时通知会发出。由于新子类这个方法被重写了,并且在内部添加了发送通知的机制。

3、苹果公司不希望将这个实现暴露在外面。于是重写了-class方法。这样依旧返回原先的class!如果不仔细看的话,是否被加入观察者的对象没什么区别。

代码

//
//  main.m
//  KVOTest
//
//  Created by dujia on 16/2/4.
//  Copyright © 2016年 杜甲. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import <objc/runtime.h>

@interface KVOTest1 : NSObject
@property (nonatomic , assign) int a;
@property (nonatomic , assign) int b;
@property (nonatomic , assign) int c;
@end

@implementation KVOTest1

@end

static NSArray *ClassMethodNames(Class c)
{
    NSMutableArray *array = [NSMutableArray array];
    
    unsigned int methodCount = 0;
    Method *methodList = class_copyMethodList(c, &methodCount);
    unsigned int i;
    for (i = 0; i < methodCount; i++) {
        [array addObject:NSStringFromSelector(method_getName(methodList[i]))];
    }
    free(methodList);
    return array;
}

static void PrintDescription(NSString *name, NSObject * obj)
{
    NSString *str = [NSString stringWithFormat:
                     @"%@: %@\n\tNSObject class %s\n\tlibobjc class %s\n\timplements methods <%@>",
                     name,
                     obj,
                     class_getName([obj class]),
                     class_getName(object_getClass(obj)),
                     [ClassMethodNames(object_getClass(obj)) componentsJoinedByString:@", "]];
    printf("%s\n", [str UTF8String]);
}

int main(int argc, char * argv[]) {
    
    KVOTest1 *a = [[KVOTest1 alloc] init];
    KVOTest1 *b = [[KVOTest1 alloc] init];
    KVOTest1 *c = [[KVOTest1 alloc] init];
    
   
    [c addObserver:c forKeyPath:@"c" options:0 context:NULL];
     [b addObserver:b forKeyPath:@"b" options:0 context:NULL];
    PrintDescription(@"a", a);
    PrintDescription(@"b", b);
    PrintDescription(@"c", c);
    
    printf("Using NSObject methods, normal setB: is %p, overridden setB: is %p\n",
           [a methodForSelector:@selector(setB:)],
           [b methodForSelector:@selector(setB:)]);
    printf("Using libobjc functions, normal setB: is %p, overridden setB: is %p\n",
           method_getImplementation(class_getInstanceMethod(object_getClass(a), @selector(setB:))),
           method_getImplementation(class_getInstanceMethod(object_getClass(b), @selector(setB:))));
    
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}


运行结果:

a: <KVOTest1: 0x7f8b69f003f0>
	NSObject class KVOTest1
	libobjc class KVOTest1
	implements methods <a, setA:, b, setB:, c, setC:>
b: <KVOTest1: 0x7f8b69f00460>
	NSObject class KVOTest1
	libobjc class NSKVONotifying_KVOTest1
	implements methods <setB:, setC:, class, dealloc, _isKVOA>
c: <KVOTest1: 0x7f8b69f00480>
	NSObject class KVOTest1
	libobjc class NSKVONotifying_KVOTest1
	implements methods <setB:, setC:, class, dealloc, _isKVOA>
Using NSObject methods, normal setB: is 0x10f4ff3b0, overridden setB: is 0x10f62ac6b
Using libobjc functions, normal setB: is 0x10f4ff3b0, overridden setB: is 0x10f62ac6b

没有加入观察者的A 输出:   libobjc class KVOTest1



代码下载 :http://download.csdn.net/detail/qqmcy/9427645

猜你喜欢

转载自blog.csdn.net/qqMCY/article/details/50635252