1. 程式人生 > >iOS KVO 實現分析

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