精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

iOS開發中KVO的內部實現

移動開發 iOS
KVO是一個很強大的工具,有時候過于強大了,尤其是有了自動觸發通知機制。現在你知道它內部是怎么實現的了,這些知識或許能幫助你更好地使用它,或在它出錯時更方便調試。

09年的一篇文章,比較深入地闡述了KVO的內部實現。

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

概覽

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

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

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

深入探究

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

  1. // gcc -o kvoexplorer -framework Foundation kvoexplorer.m 
  2.      
  3. #import <Foundation/Foundation.h> 
  4. #import <objc/runtime.h> 
  5.  
  6.  
  7. @interface TestClass : NSObject 
  8.     int x; 
  9.     int y; 
  10.     int z; 
  11. @property int x; 
  12. @property int y; 
  13. @property int z; 
  14. @end 
  15.  
  16. @implementation TestClass 
  17. @synthesize x, y, z; 
  18. @end 
  19.  
  20. static NSArray *ClassMethodNames(Class c) 
  21.     NSMutableArray *array = [NSMutableArray array]; 
  22.      
  23.     unsigned int methodCount = 0; 
  24.     Method *methodList = class_copyMethodList(c, &methodCount); 
  25.     unsigned int i; 
  26.     for(i = 0; i < methodCount; i++) 
  27.         [array addObject: NSStringFromSelector(method_getName(methodList[i]))]; 
  28.     free(methodList); 
  29.      
  30.     return array; 
  31.  
  32. static void PrintDescription(NSString *name, id obj) 
  33.     NSString *str = [NSString stringWithFormat: 
  34.         @"%@: %@\n\tNSObject class %s\n\tlibobjc class %s\n\timplements methods <%@>"
  35.         name, 
  36.         obj, 
  37.         class_getName([obj class]), 
  38.         class_getName(obj->isa), 
  39.         [ClassMethodNames(obj->isa) componentsJoinedByString:@", "]]; 
  40.     printf("%s\n", [str UTF8String]); 
  41.  
  42. int main(int argc, char **argv) 
  43.     [NSAutoreleasePool new]; 
  44.      
  45.     TestClass *x = [[TestClass alloc] init]; 
  46.     TestClass *y = [[TestClass alloc] init]; 
  47.     TestClass *xy = [[TestClass alloc] init]; 
  48.     TestClass *control = [[TestClass alloc] init]; 
  49.      
  50.     [x addObserver:x forKeyPath:@"x" options:0 context:NULL]; 
  51.     [xy addObserver:xy forKeyPath:@"x" options:0 context:NULL]; 
  52.     [y addObserver:y forKeyPath:@"y" options:0 context:NULL]; 
  53.     [xy addObserver:xy forKeyPath:@"y" options:0 context:NULL]; 
  54.      
  55.     PrintDescription(@"control", control); 
  56.     PrintDescription(@"x", x); 
  57.     PrintDescription(@"y", y); 
  58.     PrintDescription(@"xy", xy); 
  59.      
  60.     printf("Using NSObject methods, normal setX: is %p, overridden setX: is %p\n"
  61.           [control methodForSelector:@selector(setX:)], 
  62.           [x methodForSelector:@selector(setX:)]); 
  63.     printf("Using libobjc functions, normal setX: is %p, overridden setX: is %p\n"
  64.           method_getImplementation(class_getInstanceMethod(object_getClass(control), 
  65.                                    @selector(setX:))), 
  66.           method_getImplementation(class_getInstanceMethod(object_getClass(x), 
  67.                                    @selector(setX:)))); 
  68.      
  69.     return 0; 

我們從頭到尾細細看來。

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

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

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

然后打印出4個objects的description。

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

運行代碼

看看這段代碼的輸出

  1. control: <TestClass: 0x104b20> 
  2.     NSObject class TestClass 
  3.     libobjc class TestClass 
  4.     implements methods <setX:, x, setY:, y, setZ:, z> 
  5. x: <TestClass: 0x103280> 
  6.     NSObject class TestClass 
  7.     libobjc class NSKVONotifying_TestClass 
  8.     implements methods <setY:, setX:, class, dealloc, _isKVOA> 
  9. y: <TestClass: 0x104b00> 
  10.     NSObject class TestClass 
  11.     libobjc class NSKVONotifying_TestClass 
  12.     implements methods <setY:, setX:, class, dealloc, _isKVOA> 
  13. xy: <TestClass: 0x104b10> 
  14.     NSObject class TestClass 
  15.     libobjc class NSKVONotifying_TestClass 
  16.     implements methods <setY:, setX:, class, dealloc, _isKVOA> 
  17. Using NSObject methods, normal setX: is 0x195e, overridden setX: is 0x195e 
  18. Using libobjc functions, normal setX: is 0x195e, overridden setX: is 0x96a1a550 

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

然后是3個被觀察的objects。注意-class仍然顯示的是TestClass,使用object_getClass顯示了這個object的真面目:它是NSKVONotifying_TestClass的一個實例。這個NSKVONotifying_TestClass就是動態生成的subclass!

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

你會看到3個其他的方法。有之前提到過的被重寫的-class方法,假裝自己還是原來的class。還有-dealloc方法處理一些收尾工作。還有一個_isKVOA方法,看起來像是一個私有方法。

接下來,我們輸出-setX:的實現。使用-methodForSelector:返回的是相同的值。因為-setX:已經在子類被重寫了,這也就意味著methodForSelector:在內部實現中使用了-class,于是得到了錯誤的結果。

***我們通過運行時得到了不同的輸出結果。

作為一個優秀的探索者,我們進入debugger來看看這第二個方法的實現到底是怎樣的:

  1. (gdb) print (IMP)0x96a1a550 
  2. $1 = (IMP) 0x96a1a550 <_NSSetIntValueAndNotify> 

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

  1. 0013df80 t __NSSetBoolValueAndNotify 
  2. 000a0480 t __NSSetCharValueAndNotify 
  3. 0013e120 t __NSSetDoubleValueAndNotify 
  4. 0013e1f0 t __NSSetFloatValueAndNotify 
  5. 000e3550 t __NSSetIntValueAndNotify 
  6. 0013e390 t __NSSetLongLongValueAndNotify 
  7. 0013e2c0 t __NSSetLongValueAndNotify 
  8. 00089df0 t __NSSetObjectValueAndNotify 
  9. 0013e6f0 t __NSSetPointValueAndNotify 
  10. 0013e7d0 t __NSSetRangeValueAndNotify 
  11. 0013e8b0 t __NSSetRectValueAndNotify 
  12. 0013e550 t __NSSetShortValueAndNotify 
  13. 0008ab20 t __NSSetSizeValueAndNotify 
  14. 0013e050 t __NSSetUnsignedCharValueAndNotify 
  15. 0009fcd0 t __NSSetUnsignedIntValueAndNotify 
  16. 0013e470 t __NSSetUnsignedLongLongValueAndNotify 
  17. 0009fc00 t __NSSetUnsignedLongValueAndNotify 
  18. 0013e620 t __NSSetUnsignedShortValueAndNotify 

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

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

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

【移動開發視頻課程推薦】

責任編輯:閆佳明 來源: blog.leezhong
相關推薦

2011-07-25 17:07:16

iPhone KVO KVC

2013-03-25 15:06:26

iOS通信模式

2015-03-18 09:29:12

iOS開發爭議

2015-07-28 10:06:03

C#內部實現剖析

2015-10-20 11:22:34

iOS開發Git

2013-04-09 16:04:06

iOS開發SQLite知識總結

2013-01-06 09:52:43

SQLite

2014-02-19 09:59:52

iOS開發Html解析

2013-07-22 13:48:55

iOS開發ASIHTTPRequ使用Cookie

2011-07-28 10:40:40

Cocoa KVO

2011-08-19 15:09:00

IOS開發

2017-05-24 15:50:08

PythonCPython

2017-05-22 15:42:39

Python字典哈希表

2014-02-26 14:24:40

iOSUIScrollVieUIview

2014-04-23 13:30:23

類簇iOS開發

2014-06-23 10:42:56

iOS開發UIScrollVie

2011-12-01 09:25:33

iOS 5移動開發iOS

2013-04-01 10:49:51

iOS開發sqlite數據庫

2014-03-04 15:28:32

iOS開發消息傳遞機制

2016-12-12 13:41:37

iOS簡易加法開發
點贊
收藏

51CTO技術棧公眾號

亚洲精品欧美专区| 国产在线国偷精品产拍免费yy| 国产午夜精品理论片a级探花| 欧美亚洲精品一区二区| 内衣办公室在线| 久久se这里有精品| 久久免费精品视频| 欧美老女人性生活视频| 日韩精品一区国产| 欧美性猛交xxxx乱大交| 伊人久久大香线蕉综合75| 免费观看黄色一级视频| 美女在线视频一区| 久久久在线视频| 长河落日免费高清观看| heyzo欧美激情| 欧美日精品一区视频| 国产色一区二区三区| 波多野结衣在线影院| 成人网页在线观看| 国产精品揄拍500视频| 日韩欧美国产亚洲| 91精品啪在线观看国产81旧版| 日韩电影中文 亚洲精品乱码 | 久久国产一二区| 欧美成人在线免费视频| 中文字幕在线观看免费高清| 国产极品模特精品一二| 日韩一区二区三区观看| 免费黄色一级网站| 午夜激情在线播放| 洋洋av久久久久久久一区| 亚洲日本无吗高清不卡| 黄色av免费在线看| 99久久久国产精品| 国产精品久久九九| av免费在线观看不卡| 免费观看成人鲁鲁鲁鲁鲁视频| 91av在线精品| 中文在线观看免费网站| 欧美一区久久| 美女福利视频一区| 91香蕉视频网| 久久精品青草| 精品久久久91| 永久免费看mv网站入口| 日韩国产在线| 神马久久桃色视频| 神马久久久久久久久久久| 欧美一区二区三区红桃小说| 欧美精品一区二区三区久久久| 久久久久久无码精品人妻一区二区| 国产成人精选| 欧美日韩在线播| 91国产精品视频在线观看| 欧美日韩五码| 欧美色男人天堂| 香蕉视频禁止18| 欧美性www| 欧美日韩国产综合久久| 国产精品区在线| 国精品产品一区| 欧美日韩色一区| 国产精品自在自线| 久久亚洲精精品中文字幕| 91精品国产入口| 日本中文字幕有码| 高潮按摩久久久久久av免费| 亚洲第一免费播放区| 亚洲av成人无码一二三在线观看| 亚洲精品进入| 尤物tv国产一区| 欧美另类videoxo高潮| 久久久久久免费视频| 欧美另类精品xxxx孕妇| 国产网站在线看| 99精品欧美| 国产成人自拍视频在线观看| 一级黄色小视频| 国产一区二区三区免费| 国产精品v欧美精品v日韩| 天堂网在线播放| 波多野结衣在线一区| 免费国产一区| 日韩美女网站| 亚洲午夜久久久久久久久电影网| www一区二区www免费| 久久久人成影片一区二区三区在哪下载| 欧美午夜一区二区三区免费大片| 久久精品国产99久久99久久久| 97se亚洲| 中文字幕精品网| 久久精品波多野结衣| 国产亚洲午夜| 成人在线一区二区| 天堂av在线资源| **欧美大码日韩| 大j8黑人w巨大888a片| 岛国一区二区| 亚洲成人精品视频| 国产精品久久久久久成人| 综合色一区二区| 国产精品成人av性教育| 成人av无码一区二区三区| 久久网站最新地址| 男人天堂网站在线| 欧美自拍电影| 精品盗摄一区二区三区| 精品一区二区在线观看视频| 亚洲免费婷婷| 高清国产在线一区| 免费av在线| 色噜噜狠狠成人中文综合| 亚洲精品鲁一鲁一区二区三区| 欧美偷拍自拍| 午夜精品久久久久久99热| 国产又粗又长视频| 久久先锋影音av| 久久视频这里有精品| 国产成人免费视频网站视频社区| 精品性高朝久久久久久久| 欧美日韩午夜视频| 亚洲欧美成人| 极品校花啪啪激情久久| caopon在线免费视频| 欧美日韩一区精品| 精品久久久久久中文字幕人妻最新| 国产精品chinese| 成人av在线亚洲| 第三区美女视频在线| 激情成人在线视频| 最新日本中文字幕| 欧美激情aⅴ一区二区三区| 国产精品一区二区久久久 | 亚洲天堂av综合网| 日韩欧美亚洲视频| 成人午夜视频免费看| 成人污网站在线观看| 亚洲欧美专区| 精品国产一区二区三区久久狼5月 精品国产一区二区三区久久久狼 精品国产一区二区三区久久久 | 777777国产7777777| 美腿丝袜亚洲综合| 日韩电影天堂视频一区二区| 美女一区网站| 亚洲人在线观看| 男人天堂av在线播放| 91麻豆国产福利精品| www国产精品内射老熟女| 51精品国产| 国精产品一区一区三区有限在线| www.蜜臀av.com| 一区二区视频在线| 精产国品一区二区三区| 欧美日本一区| 国产高清精品一区二区| 不卡av免费观看| 日韩av在线播放资源| 精品成人免费视频| 成人a免费在线看| 日韩欧美一区三区| 亚洲综合福利| 国产精品成人av在线| 1区2区3区在线观看| 91精品一区二区三区久久久久久| 蜜桃av免费观看| 美腿丝袜一区二区三区| 青青草免费在线视频观看| 亚洲精品影片| 午夜精品一区二区三区视频免费看| 天堂中文在线资源| 色噜噜久久综合| 日韩在线一卡二卡| 国产不卡一区视频| 能在线观看的av| 久久美女精品| 国产精品精品软件视频| 成人亚洲欧美| 久久精品人人做人人爽| 成人久久精品人妻一区二区三区| 精品动漫一区二区| 一级片黄色录像| 国产高清在线观看免费不卡| 久久综合九色综合88i| 成人毛片免费看| 97人人干人人| 日韩视频网站在线观看| 欧美成人中文字幕在线| 四虎影视精品成人| 欧美精品三级日韩久久| 日韩欧美三级在线观看| 国产精品进线69影院| 91精品啪在线观看国产| 日韩电影在线观看电影| 美女av免费观看| 一级黄色小视频| 国产精品久久久久久在线| 国产精品女同一区二区三区| 永久看看免费大片| 欧美亚洲一区| 国产精品久久久影院| 免费看成人哺乳视频网站| 成人中心免费视频| 日韩免费福利视频| 欧美人在线视频| av在线资源站| 亚洲国产精品热久久| 一区二区日韩在线观看| 天天综合天天综合色| 三级黄色在线观看| 久久精品视频一区二区| 日韩欧美中文在线视频| 美女久久一区| 免费拍拍拍网站| 久久久久久免费视频| 日本不卡二区高清三区| 国产美女撒尿一区二区| 91久久久久久| www.精品国产| 国产91免费看片| 黄视频免费在线看| 不卡毛片在线看| 一广人看www在线观看免费视频| 国产视频精品在线| 欧美一级性视频| 日韩欧美在线影院| 国产精品久久久久久久久毛片 | 久久精品无码av| 五月综合激情日本mⅴ| 欧美三级日本三级| 中文字幕在线不卡国产视频| 最新中文字幕av| 久久久久国产精品免费免费搜索| 男人网站在线观看| 国产成人av一区二区三区在线| 岛国av免费在线| 久久精品99国产精品| 黑人粗进入欧美aaaaa| 香蕉久久久久久久av网站| 91九色在线观看视频| 最新亚洲激情| 国产免费黄色av| 99在线精品免费视频九九视| 国产真人做爰毛片视频直播| 国产精品啊啊啊| 乱熟女高潮一区二区在线| 女同性一区二区三区人了人一| 男人的天堂成人| 中文字幕人成人乱码| 黄色网络在线观看| 亚洲精品a级片| 国产911在线观看| 亚洲天堂偷拍| 国产亚洲天堂网| 日韩国产欧美在线播放| 日本中文字幕高清| 九九精品视频在线看| 亚欧美一区二区三区| 国产aⅴ精品一区二区三区色成熟| 风韵丰满熟妇啪啪区老熟熟女| 丁香激情综合国产| 成年人的黄色片| 久久久不卡网国产精品二区| 2019男人天堂| 亚洲男人的天堂一区二区| 欧美成人三级视频| 婷婷综合另类小说色区| 亚洲欧美一区二区三区在线观看| 日本高清不卡视频| 一区二区三区免费在线视频| 欧美一级国产精品| 日本精品一区二区在线观看| 亚洲欧美国产高清va在线播 | 欧美日韩成人黄色| 爱啪视频在线观看视频免费| 欧美综合第一页| 成人全视频免费观看在线看| 91系列在线播放| 老司机精品在线| 亚洲精品一区二区毛豆| 欧美~级网站不卡| 99爱视频在线| 国产在线精品一区二区夜色| 影音先锋资源av| 久久久激情视频| 欧美精品一区二区蜜桃| 欧美日韩国产精品一区| 在线免费观看日韩视频| 精品国产乱码久久久久久影片| 日韩欧美电影在线观看| 日韩在线中文字| 美女网站在线看| 91精品国产综合久久香蕉的用户体验 | 少妇精品一区二区三区| 国产精品久久久久7777按摩| 日韩 欧美 亚洲| 欧美日韩高清一区二区三区| 欧美一区二不卡视频| www欧美日韩| 亚洲一区资源| 国产成人精品日本亚洲11| 北条麻妃国产九九九精品小说| 8x8ⅹ国产精品一区二区二区| 久久九九国产| 亚洲熟女一区二区| 综合久久一区二区三区| 日韩 国产 欧美| 精品国内片67194| 免费av在线网站| 国产精品69久久| 视频福利一区| 亚洲熟妇无码av在线播放| 免费看欧美女人艹b| 在线精品一区二区三区| 亚洲欧美激情视频在线观看一区二区三区 | 99视频精品全国免费| 精品人妻一区二区三区四区在线| 国产美女视频91| 中文字幕精品亚洲| 色婷婷av一区| 色视频在线观看免费| 欧美激情精品久久久久久免费印度 | 午夜精品婷婷| 在线观看日本一区二区| 久久久www免费人成精品| 国产成人愉拍精品久久| 日韩欧美成人激情| 国内精品久久久久久野外| 国产精品看片资源| 九九免费精品视频在线观看| 日韩中文字幕在线视频观看| 丁香桃色午夜亚洲一区二区三区| 男人的天堂久久久| 制服丝袜亚洲色图| 欧洲美女少妇精品| 国产日韩欧美电影在线观看| 日韩国产一区二区三区| 美女网站色免费| 国产精品婷婷午夜在线观看| 中文字幕av影视| 一区国产精品视频| 成人影院入口| 欧美激情专区| 久久综合伊人| 国产成人福利在线| 欧洲亚洲国产日韩| 在线观看a视频| 亚洲一卡二卡三卡四卡无卡久久| 欧美亚洲视频一区| 999亚洲国产精| 朝桐光av一区二区三区| 国产精品美女久久福利网站| 欧美三日本三级少妇99| 日韩精品在线观看一区二区| 345成人影院| 色一情一乱一伦一区二区三欧美 | 2021久久精品国产99国产精品| 欧美亚洲色图校园春色| 欧美极品欧美精品欧美图片| 久久久久久久久久久电影| 亚洲午夜在线播放| www.国产精品一二区| 久久丁香四色| 成人性免费视频| 久久久三级国产网站| 中文字幕欧美在线观看| 久久综合88中文色鬼| 亚洲一区电影| 国产免费毛卡片| 中文字幕av资源一区| 国产伦理一区二区| 久久久久亚洲精品成人网小说| 中文字幕精品影院| 999在线观看| 亚洲午夜电影在线观看| 日本中文字幕电影在线观看 | 欧美激情性做爰免费视频| 99这里只有精品视频| 北条麻妃在线观看| 亚洲欧洲国产日韩| 日本精品久久久久久| 国产精品视频精品| 欧美色图首页| 熟女俱乐部一区二区视频在线| 欧美日韩mp4| av福利在线导航| 视频一区二区精品| 成人永久aaa| 中文字幕精品一区二区精| 九九久久精品一区| 国产欧美一区| 国产情侣久久久久aⅴ免费| 色av一区二区| 国产经典三级在线| 久久久久五月天| 国产精品国内免费一区二区三区| 欧美大片免费播放器| 在线播放亚洲一区| 成人免费网站视频| 国产精品无码免费专区午夜| 中文一区二区在线观看|