成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

詳解:Objective-C Class Ivar Layout

移動開發 iOS
這次探索源于一個朋友問的問題,當我們定義一個類的實例變量的時候,可以指定其修飾符:

這次探索源于一個朋友問的問題,當我們定義一個類的實例變量的時候,可以指定其修飾符:

  1. @interface Sark : NSObject { 
  2. __strong id _gayFriend; // 無修飾符的對象默認會加 __strong 
  3. __weak id _girlFriend; 
  4. __unsafe_unretained id _company; 
  5. @end 

這使得 ivar (instance variable) 可以像屬性一樣在 ARC 下進行正確的引用計數管理。

那么問題來了,假如這個類是動態生成的:

  1. Class class = objc_allocateClassPair(NSObject.class"Sark"0); 
  2. class_addIvar(class"_gayFriend", sizeof(id), log2(sizeof(id)), @encode(id)); 
  3. class_addIvar(class"_girlFriend", sizeof(id), log2(sizeof(id)), @encode(id)); 
  4. class_addIvar(class"_company", sizeof(id), log2(sizeof(id)), @encode(id)); 
  5. objc_registerClassPair(class); 

該如何像上面一樣來添加 ivar 的屬性修飾符呢?

刨根問底了一下,發現 ivar 的修飾信息存放在了 Class 的 Ivar Layout 中:

  1. struct class_ro_t { 
  2. uint32_t flags; 
  3. uint32_t instanceStart; 
  4. uint32_t instanceSize; 
  5. #ifdef __LP64__ 
  6. uint32_t reserved; 
  7. #endif 
  8. const uint8_t * ivarLayout; // <- 記錄了哪些是 strong 的 ivar 
  9.  
  10. const char * name; 
  11. const method_list_t * baseMethods; 
  12. const protocol_list_t * baseProtocols; 
  13. const ivar_list_t * ivars; 
  14. const uint8_t * weakIvarLayout; // <- 記錄了哪些是 weak 的 ivar 
  15. const property_list_t *baseProperties; 
  16. }; 

ivarLayout 和 weakIvarLayout 分別記錄了哪些 ivar 是 strong 或是 weak,都未記錄的就是基本類型和 __unsafe_unretained 的對象類型。

這兩個值可以通過 runtime 提供的幾個 API 來訪問:

  1. const uint8_t *class_getIvarLayout(Class cls) 
  2. const uint8_t *class_getWeakIvarLayout(Class cls) 
  3. void class_setIvarLayout(Class cls, const uint8_t *layout) 
  4. void class_setWeakIvarLayout(Class cls, const uint8_t *layout) 

但我們幾乎沒可能用到這幾個 API,IvarLayout 的值由 runtime 確定,沒必要關心它的存在,但為了解決上述問題,我們試著破解了 IvarLayout 的編碼方式。

舉個例子說明,若類定義為:

  1. @interface Foo : NSObject { 
  2. __strong id ivar0; 
  3. __weak id ivar1; 
  4. __weak id ivar2; 
  5. @end 

則儲存 strong ivar 的 ivarLayout 的值為 0x012000

儲存 weak ivar 的 weakIvarLayout 的值為 0x1200

一個 uint8_t 在 16 進制下是兩位,所以編碼的值每兩位一對兒,以上面的 ivarLayout 為例:

前兩位 01 表示有 0 個非 strong 對象和 1 個 strong 對象

之后兩位 20 表示有 2 個非 strong 對象和 0 個 strong 對象

***兩位 00 為結束符,就像 cstring 的 \0 一樣

同理,上面的 weakIvarLayout:

前兩位 12 表示有 1 個非 weak 對象和接下來連續 2 個 weak 對象

00 結束符

這樣,用兩個 layout 編碼值就可以排查出一個 ivar 是屬于 strong 還是 weak 的,若都沒有找到,就說明這個對象是 unsafe_unretained.

做個練習,若類定義為:

  1. @interface Bar : NSObject { 
  2. __weak id ivar0; 
  3. __strong id ivar1; 
  4. __unsafe_unretained id ivar2; 
  5. __weak id ivar3; 
  6. __strong id ivar4; 
  7. @end 

則儲存 strong ivar 的 ivarLayout 的值為 0x012100

儲存 weak ivar 的 weakIvarLayout 的值為 0x01211000

  1. Class class = objc_allocateClassPair(NSObject.class"Sark"0); 
  2. class_addIvar(class"_gayFriend", sizeof(id), log2(sizeof(id)), @encode(id)); 
  3. class_addIvar(class"_girlFriend", sizeof(id), log2(sizeof(id)), @encode(id)); 
  4. class_addIvar(class"_company", sizeof(id), log2(sizeof(id)), @encode(id)); 
  5. class_setIvarLayout(class, (const uint8_t *)"\x01\x12"); // <--- new 
  6. class_setWeakIvarLayout(class, (const uint8_t *)"\x11\x10"); // <--- new 
  7. objc_registerClassPair(class); 

本以為解決了這個問題,但是 runtime 繼續打臉,strong 和 weak 的內存管理并沒有生效,繼續研究發現, class 的 flags 中有一個標記位記錄這個類是否 ARC,正常編譯的類,且標識了 -fobjc-arc flag 時,這個標記位為 1,而動態創建的類并沒有設置它。所以只能繼續黑魔法,運行時把這個標記位設置上,探索過程不贅述了,實現如下:
 

  1. static void fixup_class_arc(Class class) { 
  2. struct { 
  3. Class isa; 
  4. Class superclass; 
  5. struct { 
  6. void *_buckets; 
  7. uint32_t _mask; 
  8. uint32_t _occupied; 
  9. } cache; 
  10. uintptr_t bits; 
  11. } *objcClass = (__bridge typeof(objcClass))class
  12. #if !__LP64__ 
  13. #define FAST_DATA_MASK 0xfffffffcUL 
  14. #else 
  15. #define FAST_DATA_MASK 0x00007ffffffffff8UL 
  16. #endif 
  17. struct { 
  18. uint32_t flags; 
  19. uint32_t version; 
  20. struct { 
  21. uint32_t flags; 
  22. } *ro; 
  23. } *objcRWClass = (typeof(objcRWClass))(objcClass->bits & FAST_DATA_MASK); 
  24. #define RO_IS_ARR 1flags |= RO_IS_ARR; 

把這個 fixup 放在 objc_registerClassPair(class); 之后,這個動態的類終于可以像靜態編譯的類一樣操作 ivar 了,可以測試一下:

  1. id sark = [class new]; 
  2. Ivar weakIvar = class_getInstanceVariable(class"_girlFriend"); 
  3. Ivar strongIvar = class_getInstanceVariable(class"_gayFriend"); 
  4. id girl = [NSObject new]; 
  5. id boy = [NSObject new]; 
  6. object_setIvar(sark, weakIvar, girl); 
  7. object_setIvar(sark, strongIvar, boy); 
  8. // ARC 在這里會釋放大括號內的 girl,boy 
  9. // 輸出:weakIvar 為 nil,strongIvar 有值 
  10. NSLog(@"%@, %@", object_getIvar(sark, weakIvar), object_getIvar(sark, strongIvar)); 

Done.

責任編輯:chenqingxiang 來源: sunnyxx的技術博客
相關推薦

2011-07-29 16:16:30

Objective-c block

2011-08-17 10:58:59

Objective-C構造函數

2011-08-17 10:29:39

Objective-C預處理

2011-07-18 16:36:51

Objective-C XCode

2014-04-01 10:50:42

iOS開發runtimeObjective-C

2011-08-09 15:53:28

2011-08-04 13:38:01

Objective-C C++

2011-07-08 18:44:09

Objective-C Self Super

2011-08-16 13:43:40

Objective-C文件cocoa

2011-08-16 10:23:04

Objective-CNSAutoreleaXcode常用鍵

2011-07-27 16:55:12

Objective-c 閉包

2011-08-01 17:11:43

Objective-C 函數

2011-08-15 14:32:42

Objective-C委托協議

2014-04-28 09:56:56

Objective-CiOS命名空間

2011-08-17 11:05:22

Objective-C方法

2011-07-29 15:47:21

iPhone開發 Objective- C

2013-06-20 10:40:32

Objective-C實現截圖

2013-03-27 12:54:00

iOS開發Objective-C

2011-05-11 15:58:34

Objective-C

2011-05-11 11:20:26

Objective-C
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美一级欧美一级在线播放 | 国产精品视频免费播放 | 国产资源一区二区三区 | 久久国产精品一区二区 | 色综合色综合色综合 | 一级做a爰片性色毛片视频停止 | 国产亚洲一区二区精品 | 精品国产一区二区三区在线观看 | 日韩精品区 | 国产乱码精品一区二区三区忘忧草 | 亚洲精品中文在线 | 日本午夜精品一区二区三区 | av入口| 日日夜夜精品免费视频 | 欧美中文字幕一区二区三区 | 久久精品国产亚洲a | 91av导航 | www.夜夜骑| 日韩精品免费视频 | 国产高清在线 | 91久久久久久 | 99re在线视频免费观看 | www.玖玖玖| 亚洲狠狠 | 澳门永久av免费网站 | 国精日本亚洲欧州国产中文久久 | 国产福利91精品一区二区三区 | 国产精品一区在线观看 | 精品国产乱码久久久久久丨区2区 | 福利国产 | 日本韩国欧美在线观看 | 亚洲精品99999 | 少妇无套高潮一二三区 | va在线 | 久久国产精品一区二区三区 | 在线小视频 | 精品美女久久久久久免费 | 福利一区视频 | 黄色片网站国产 | 男女羞羞视频免费看 | 一区二区视频在线观看 |