欧美vvv,亚洲第一成人在线,亚洲成人欧美日韩在线观看,日本猛少妇猛色XXXXX猛叫

新聞資訊

    原文鏈接:

    09年的一篇文章,比較深入地闡述了KVO的內(nèi)部實現(xiàn)。

    KVO是實現(xiàn)Cocoa 的基礎,它提供了一種方法,當某個屬性改變時,相應的會被通知到。在其他語言中,這種觀察者模式通常需要單獨實現(xiàn),而在-C中,通常無須增加額外代碼即可使用。

    概覽

    這是怎么實現(xiàn)的呢?其實這都是通過-C強大的運行時()實現(xiàn)的。當你第一次觀察某個時,會創(chuàng)建一個新的繼承原先class的。在這個新的class中,它重寫了所有被觀察的key,然后將的isa指針指向新創(chuàng)建的class(這個指針告訴-C運行時某個到底是哪種類型的)。所以神奇地變成了新的子類的實例。

    這些被重寫的方法實現(xiàn)了如何通知觀察者們。當改變一個key時,會觸發(fā)方法,但這個方法被重寫了,并且在內(nèi)部添加了發(fā)送通知機制。(當然也可以不走方法,比如直接修改iVar,但不推薦這么做)。

    有意思的是:蘋果不希望這個機制暴露在外部。除了,這個動態(tài)生成的子類同時也重寫了-class方法,依舊返回原先的class!如果不仔細看的話,被KVO過的看起來和原先的沒什么兩樣。

    深入探究

    下面來看看這些是如何實現(xiàn)的。我寫了個程序來演示隱藏在KVO背后的機制。

     gcc -o kvoexplorer -framework Foundation kvoexplorer.m 
     
    #import  
    #import  
    @interface TestClass : NSObject 
    { 
        int x; 
        int y; 
        int z; 
    } 
    @property int x; 
    @property int y; 
    @property int z; 
    @end 
    

    c 單例模式實現(xiàn)_c實現(xiàn)觀察者模式_編程語言實現(xiàn)模式pdf

    @implementation TestClass @synthesize x, y, z; @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, id obj) { NSString *str = [NSString stringWithFormat: @"%@: %@\n\tNSObject class %s\n\tlibobjc class %s\n\timplements methods <%@>", name,

    c實現(xiàn)觀察者模式_c 單例模式實現(xiàn)_編程語言實現(xiàn)模式pdf

    obj, class_getName([obj class]), class_getName(obj->isa), [ClassMethodNames(obj->isa) componentsJoinedByString:@", "]]; printf("%s\n", [str UTF8String]); } int main(int argc, char **argv) { [NSAutoreleasePool new]; TestClass *x = [[TestClass alloc] init]; TestClass *y = [[TestClass alloc] init]; TestClass *xy = [[TestClass alloc] init]; TestClass *control = [[TestClass alloc] init]; [x addObserver:x forKeyPath:@"x" options:0 context:NULL]; [xy addObserver:xy forKeyPath:@"x" options:0 context:NULL]; [y addObserver:y forKeyPath:@"y" options:0 context:NULL]; [xy addObserver:xy forKeyPath:@"y" options:0 context:NULL]; PrintDescription(@"control", control); PrintDescription(@"x", x); PrintDescription(@"y", y);

    編程語言實現(xiàn)模式pdf_c實現(xiàn)觀察者模式_c 單例模式實現(xiàn)

    PrintDescription(@"xy", xy); printf("Using NSObject methods, normal setX: is %p, overridden setX: is %p\n", [control methodForSelector:@selector(setX:)], [x methodForSelector:@selector(setX:)]); printf("Using libobjc functions, normal setX: is %p, overridden setX: is %p\n", method_getImplementation(class_getInstanceMethod(object_getClass(control), @selector(setX:))), method_getImplementation(class_getInstanceMethod(object_getClass(x), @selector(setX:)))); return 0; }

    我們從頭到尾細細看來。

    首先定義了一個的類,它有3個屬性。

    然后定義了一些方便調(diào)試的方法。使用-C運行時方法來遍歷一個class,得到方法列表。注意,這些方法不包括父類的方法。打印的所有信息,包括class信息(包括-class和通過運行時得到的class),以及這個class實現(xiàn)的方法。

    然后創(chuàng)建了4個實例,每一個都使用了不同的觀察方式。x實例有一個觀察者觀察xkey,y, xy也類似。為了做比較,zkey沒有觀察者。最后實例沒有任何觀察者。

    然后打印出4個的。

    之后繼續(xù)打印被重寫的內(nèi)存地址,以及未被重寫的的內(nèi)存地址做比較。這里做了兩次,是因為-:沒能得到重寫的方法。KVO試圖掩蓋它實際上創(chuàng)建了一個新的這個事實!但是使用運行時的方法就原形畢露了。

    運行代碼

    看看這段代碼的輸出

    control:  
    NSObject class TestClass 
    

    編程語言實現(xiàn)模式pdf_c 單例模式實現(xiàn)_c實現(xiàn)觀察者模式

    libobjc class TestClass implements methods x: NSObject class TestClass libobjc class NSKVONotifying_TestClass implements methods y: NSObject class TestClass libobjc class NSKVONotifying_TestClass implements methods xy: NSObject class TestClass libobjc class NSKVONotifying_TestClass implements methods Using NSObject methods, normal setX: is 0x195e, overridden setX: is 0x195e Using libobjc functions, normal setX: is 0x195e, overridden setX: is 0x96a1a550

    首先,它輸出了,沒有任何問題,它的class是,并且實現(xiàn)了6個set/get方法。

    然后是3個被觀察的。注意-class仍然顯示的是,使用顯示了這個的真面目:它是lass的一個實例。這個lass就是動態(tài)生成的!

    注意,它是如何實現(xiàn)這兩個被觀察的的。你會發(fā)現(xiàn),它很聰明,沒有重寫-setZ:c實現(xiàn)觀察者模式,雖然它也是個,因為它沒有被觀察。同時注意到,3個實例對應的是同一個class,也就是說兩個都被重寫了,盡管其中的兩個實例只觀察了一個屬性。這會帶來一點效率上的問題,因為即使沒有被觀察的也會走被重寫的,但蘋果顯然覺得這比分開生成動態(tài)的更好,我也覺得這是個正確的選擇。

    你會看到3個其他的方法。有之前提到過的被重寫的-class方法c實現(xiàn)觀察者模式,假裝自己還是原來的class。還有-方法處理一些收尾工作。還有一個方法,看起來像是一個私有方法。

    接下來,我們輸出-setX:的實現(xiàn)。使用-:返回的是相同的值。因為-setX:已經(jīng)在子類被重寫了,這也就意味著:在內(nèi)部實現(xiàn)中使用了-class,于是得到了錯誤的結(jié)果。

    最后我們通過運行時得到了不同的輸出結(jié)果。

    作為一個優(yōu)秀的探索者,我們進入來看看這第二個方法的實現(xiàn)到底是怎樣的:

    編程語言實現(xiàn)模式pdf_c 單例模式實現(xiàn)_c實現(xiàn)觀察者模式

    (gdb) print (IMP)

    $1 = (IMP)

    看起來是一個內(nèi)部方法,對使用nm -a得到一個完整的私有方法列表:

    0013df80 t __NSSetBoolValueAndNotify 
    000a0480 t __NSSetCharValueAndNotify 
    0013e120 t __NSSetDoubleValueAndNotify 
    0013e1f0 t __NSSetFloatValueAndNotify 
    000e3550 t __NSSetIntValueAndNotify 
    0013e390 t __NSSetLongLongValueAndNotify 
    0013e2c0 t __NSSetLongValueAndNotify 
    00089df0 t __NSSetObjectValueAndNotify 
    0013e6f0 t __NSSetPointValueAndNotify 
    0013e7d0 t __NSSetRangeValueAndNotify 
    0013e8b0 t __NSSetRectValueAndNotify 
    0013e550 t __NSSetShortValueAndNotify 
    0008ab20 t __NSSetSizeValueAndNotify 
    0013e050 t __NSSetUnsignedCharValueAndNotify 
    0009fcd0 t __NSSetUnsignedIntValueAndNotify 
    0013e470 t __NSSetUnsignedLongLongValueAndNotify 
    0009fc00 t __NSSetUnsignedLongValueAndNotify 
    0013e620 t __NSSetUnsignedShortValueAndNotify 
    

    這個列表也能發(fā)現(xiàn)一些有趣的東西。比如蘋果為每一種 type都寫了對應的實現(xiàn)。-C的會用到的其實只有,但需要一整套來對應剩下的,而且看起來也沒有實現(xiàn)完全,比如long 或_Bool都沒有。甚至沒有為通用指針類型( type)提供方法。所以,不在這個方法列表里的屬性其實是不支持KVO的。

    KVO是一個很強大的工具,有時候過于強大了,尤其是有了自動觸發(fā)通知機制?,F(xiàn)在你知道它內(nèi)部是怎么實現(xiàn)的了,這些知識或許能幫助你更好地使用它,或在它出錯時更方便調(diào)試。

    如果你打算使用KVO,或許可以看一下我的另一篇文章Key-Value Done Right

網(wǎng)站首頁   |    關于我們   |    公司新聞   |    產(chǎn)品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區(qū)    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有