OC對象探究03:isa 解析

提前準(zhǔn)備

為了探究對象在底層的實現(xiàn)方式,此次使用clang來進(jìn)行探究。相關(guān)語句clang -rewrite-objc main.m -o main.cpp ,在終端中進(jìn)入工程目錄main.m所在的路徑中,執(zhí)行上面的語句蝶防,就會生成一個main.cpp的C++文件,該文件就是main.m文件的底層實現(xiàn)方式明吩。

main.cpp探究

通過clang之后的main.cpp 文件可以看到如下代碼:

struct YKPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *_name;
};

可以看出我們創(chuàng)建的YKPerson類在底部被編譯成了YKPerson_IMPL的結(jié)構(gòu)體间学,name屬性成為結(jié)構(gòu)體的屬性。所以我們可以得到第一個結(jié)論印荔,對象在底層被編譯成了結(jié)構(gòu)體低葫,對象在底層是以結(jié)構(gòu)體的形式存在,而NSObject_ IVARS是在內(nèi)部默認(rèn)全部都有的屬性isa仍律。

聯(lián)合體位域

在日常開發(fā)中少不了在類中聲明一些布爾或其他類型的屬性用于判斷嘿悬。為了更高的利用內(nèi)存,我們可以合理使用聯(lián)合體位域的方式來減少對內(nèi)存的占用水泉。

@property (nonatomic, assign) BOOL front;
@property (nonatomic, assign) BOOL back;
@property (nonatomic, assign) BOOL left;
@property (nonatomic, assign) BOOL right;
union {
    char bits;
    struct {
          char front : 1;
          char back  : 2;
          char left  : 3;
          char right : 4;
    }
} _direction;

例如以上代碼善涨,日常開發(fā)中一般會使用第一段代碼聲明(front,back,left,right)四個屬性來做相應(yīng)的方向判斷,并且在相應(yīng)的setter草则,getter方法中進(jìn)行相應(yīng)的操作钢拧,因為BOOL類型是4字節(jié)類型,所以它們需要占用4*4 = 16字節(jié) = 128位炕横,只是為了做一個方向判斷時源内,這個內(nèi)存占用量其實也是不少的。所以這個時候我們可以用到聯(lián)合體位域 看锉。
在第二段代碼中姿锭,因為char類型的數(shù)據(jù)為1字節(jié),所以總共占用了5字節(jié)伯铣。每一個屬性后面的數(shù)字代表的是所在的位置(例如:0000 1111,第一位代表front轮纫,第二位代表back腔寡,第三位代表3,第四位代表right)掌唾。使用聯(lián)合體位域時需要配合相應(yīng)的方法來對聯(lián)合體位域中的屬性進(jìn)行相應(yīng)設(shè)置放前。

  • 結(jié)構(gòu)體
    優(yōu)點:所有的變量是“共存”的忿磅,全面;
    缺點:struct內(nèi)存空間的分配是粗放的凭语,不管用不用葱她,全分配。
  • 聯(lián)合體
    優(yōu)點:各個變量是“互斥”的似扔,內(nèi)存使用更為精細(xì)靈活吨些,節(jié)省了內(nèi)存空間;
    缺點:不夠“包容”

isa分析

之前我們已經(jīng)分析了對象在alloc時調(diào)用instanceSize計算內(nèi)存空間炒辉,calloc像系統(tǒng)申請內(nèi)存豪墅,接下來就是講開辟的內(nèi)存與對象類進(jìn)行關(guān)聯(lián)。通過源碼分析黔寇,調(diào)用initInstanceIsa后在方法initIsa中進(jìn)行處理偶器,因此initIsa為核心方法。在該方法中主要是對isa的賦值操作,接下來對該方法做主要分析缝裤。屬性isaisa_t類型屏轰,在該方法中對聯(lián)合體isa_t isa中的相關(guān)屬性進(jìn)行了一些賦值操作。

union isa_t {
    isa_t(){}
    isa_t(uintptr_t value) : bits(value) { }
    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  //defined in isa.h
    };
#endif
}

以上為聯(lián)合體isa_t的定義憋飞,屬性clsbits 互斥亭枷,只有當(dāng)nonpointer不存在時cls才會被賦值,當(dāng)nonpointer存在時搀崭,講給bit賦值一個宏定義的ISA_INDEX_MAGIC_VALUE 0x001d800000000001ULL叨粘。重點在ISA_BITFIELD,以下是以x86架構(gòu)下的關(guān)于相關(guān)定義瘤睹,并對內(nèi)部結(jié)構(gòu)進(jìn)行解讀升敲。

# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;                                         \
      uintptr_t has_assoc         : 1;                                         \
      uintptr_t has_cxx_dtor      : 1;                                         \
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      uintptr_t magic             : 6;                                         \
      uintptr_t weakly_referenced : 1;                                         \
      uintptr_t deallocating      : 1;                                         \
      uintptr_t has_sidetable_rc  : 1;                                         \
      uintptr_t extra_rc          : 8
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)
  • nonpointer :表示是否對isa指針開啟指針優(yōu)化,0:純isa指針轰传,1:不止是類對象地址驴党,isa包含了類信息、對象的引用計數(shù)等
  • has_assoc : 關(guān)聯(lián)對象標(biāo)志位获茬,0沒有港庄,1存在
  • has_cxx_dtor : 該對象是否有C++或者OBJC的析構(gòu)器,如果有析構(gòu)函數(shù)恕曲,則需要做析構(gòu)邏輯鹏氧,如果沒有,則可以更快的釋放對象
  • shiftcls :在x86架構(gòu)下占用44位內(nèi)存佩谣。存儲類指針的值把还。開啟指針優(yōu)化的情況下,arm64架構(gòu)下占用33位內(nèi)存。
  • magic:用于調(diào)試器判斷當(dāng)前對象是真的對象還是沒有初始化的空間吊履。
  • weakly_referenced :指對象是否被指向或者曾經(jīng)指向一個ARC的弱變量安皱,沒有弱引用的對象可以更快釋放。
  • deallocating:標(biāo)志對象是否正在釋放內(nèi)存艇炎。
  • has_sidetable_rc :當(dāng)對象引用計數(shù)大于10時酌伊,則需要借用該變量存儲進(jìn)位。
  • extra_rc:當(dāng)表示該對象的引用計數(shù)時缀踪,實際上是引用計數(shù)值減1居砖,例如,如果對象的引用計數(shù)為10辜贵,那么extra_rc為9.如果引用計數(shù)大于10悯蝉,則需要使用到上面的has_sidetable_rc
LGPerson.png

在之前的文章中講到對象調(diào)用alloc時托慨,在_class_createInstanceFromZone 中與類進(jìn)行關(guān)聯(lián)鼻由,通過調(diào)試obj為返回結(jié)果,0x001d8001000020f1isa厚棵,我們將isa 進(jìn)行位移計算蕉世,目的是得到isa_t 中的shiftcls,再以16進(jìn)制打印傳入的cls時我們發(fā)現(xiàn)此時的shiftcls就是我們的類婆硬,代表此時我們自定義的類已經(jīng)被系統(tǒng)關(guān)聯(lián)狠轻,并初始化了內(nèi)存空間。

拓展 (clang)

  • clang -rewrite-objc main.m -o main.cpp 把目標(biāo)文件編譯成c++文件
  • UIKit報錯問題
    • clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platfroms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk main.m 通過找到當(dāng)前版本Xcode下對應(yīng)的SDK來進(jìn)行生成彬犯,一般在頭文件中包含UIKit時出現(xiàn)該問題
  • xcode安裝的時候順帶安裝了xcrun命令向楼,xcrun命令在clang的基礎(chǔ)上進(jìn)行了 一些封裝,要更好用一些
  • xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp (模擬器)
  • xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main- arm64.cpp (手機(jī))

結(jié)論

從以上可以得到在調(diào)用initIsa時是將系統(tǒng)為類創(chuàng)建的內(nèi)存以及設(shè)置一些類的信息并與當(dāng)前類進(jìn)行關(guān)聯(lián)谐区。所以在isa 中保存了類的所有信息湖蜕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市宋列,隨后出現(xiàn)的幾起案子昭抒,更是在濱河造成了極大的恐慌,老刑警劉巖炼杖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灭返,死亡現(xiàn)場離奇詭異,居然都是意外死亡坤邪,警方通過查閱死者的電腦和手機(jī)熙含,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來罩扇,“玉大人婆芦,你說我怎么就攤上這事怕磨∥辜ⅲ” “怎么了消约?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長员帮。 經(jīng)常有香客問我或粮,道長,這世上最難降的妖魔是什么捞高? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任氯材,我火速辦了婚禮,結(jié)果婚禮上硝岗,老公的妹妹穿的比我還像新娘氢哮。我一直安慰自己,他們只是感情好型檀,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布冗尤。 她就那樣靜靜地躺著,像睡著了一般胀溺。 火紅的嫁衣襯著肌膚如雪裂七。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天仓坞,我揣著相機(jī)與錄音背零,去河邊找鬼。 笑死无埃,一個胖子當(dāng)著我的面吹牛徙瓶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嫉称,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼侦镇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了澎埠?” 一聲冷哼從身側(cè)響起虽缕,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒲稳,沒想到半個月后氮趋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡江耀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年剩胁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祥国。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡昵观,死狀恐怖晾腔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情啊犬,我是刑警寧澤灼擂,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站觉至,受9級特大地震影響剔应,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜语御,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一峻贮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧应闯,春花似錦纤控、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至惜辑,卻和暖如春唬涧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盛撑。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工碎节, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人抵卫。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓狮荔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親介粘。 傳聞我的和親對象是個殘疾皇子殖氏,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350