初探OC底層原理之對象本質(zhì)&isa分析

一.了解clang

  • Clang是?個C語?、C++、Objective-C語?的輕量級編譯器。源代碼發(fā)布于BSD協(xié)議下。
    Clang將?持其普通lambda表達式、返回類型的簡化處理以及更好的處
    理constexpr關鍵字
  • Clang是?個由Apple主導編寫,基于LLVM的C/C++/Objective-C編譯器
  • 2013年4?,Clang已經(jīng)全??持C++11標準,并開始實現(xiàn)C++1y特性(也就是C++14,這是
    C++的下?個?更新版本)。Clang將?持其普通lambda表達式、返回類型的簡化處理以及更
    好的處理constexpr關鍵字。 [2]
    Clang是?個C++編寫、基于LLVM、發(fā)布于LLVM BSD許可證下的C/C++/Objective-C/
    Objective-C++編譯器。它與GNU C語?規(guī)范?乎完全兼容(當然,也有部分不兼容的內(nèi)容,
    包括編譯命令選項也會有點差異),并在此基礎上增加了額外的語法特性,?如C函數(shù)重載
    (通過attribute((overloadable))來修飾函數(shù)),其?標(之?)就是超越GCC

二.編譯oc文件為c++文件

  • 1.直接命令行編譯
clang -rewrite-objc main.m -o main.cpp 把?標?件編譯成c+
+?件
 
  • 2.如果有系統(tǒng)庫會報錯 如:(UIKit報錯問題)
clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot /
Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk main.m

  • 3.用xcode 編譯(xcode安裝的時候順帶安裝了xcrun命令,xcrun命令在clang的基礎上進?了
    ?些封裝,要更好??些)
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 (?機)

三.分析c++文件

16238094496702.jpg
  • 從上圖可以看出對象在底層的本質(zhì)是一個結構體
  • 跟蹤NSObject_IMPL結構類型可以看到如圖下:


    16238097133294.jpg
16238098453640.jpg
  • 從上面圖可以得出objc 底層調(diào)用就是objc_object


    16238101883395.jpg
  • id class = [class new] 為什么我們id 類型可以獲取所有的屬性類型而且不需要加,因為他的底層就是id

@property (nonatomic, strong) NSString *nikeName

  • 為什么屬性自帶set 和get 方法 根據(jù)底層跟蹤如下
static NSString * _I_LGPerson_nikeName(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_nikeName)); }
static void _I_LGPerson_setNikeName_(LGPerson * self, SEL _cmd, NSString *nikeName) { (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_nikeName)) = nikeName; }

  • 總結:對象本質(zhì)就是一個結構體,屬性成員變量實現(xiàn)了get和和set方法.
  • 流程分析 :
  • LGPerson -->找到LGPerson_IMPL -->NSObject_IMPL--->Class

了解結構體和聯(lián)合體

  • 結構體(struct)中所有變量是“共存”的——優(yōu)點是“有容乃?”,
    全?;缺點是struct內(nèi)存空間的分配是粗放的,不管?不?,全分配
  • 聯(lián)合體(union)中是各變量是“互斥”的——缺點就是不夠“包容”;但優(yōu)點是內(nèi)存使?更為精細靈活,也節(jié)省了內(nèi)存空間
16238123362926.jpg
  • 從上圖輸出可以得出互斥更加節(jié)省內(nèi)存空間(BOOL front: 1; 1代表一個byte,8個byte=1字節(jié))

isa 的分析

  • 以arm64為例
    16238138660021.jpg
  • nonpointer:表示是否對 isa 指針開啟指針優(yōu)化
    0:純isa指針,1:不?是類對象地址,isa 中包含了類信息、對象的引?計數(shù)等

  • has_assoc:關聯(lián)對象標志位,0沒有,1存在

  • has_cxx_dtor:該對象是否有 C++ 或者 Objc 的析構器,如果有析構函數(shù),則需要做析構邏輯,
    如果沒有,則可以更快的釋放對象

  • shiftcls: 存儲類指針的值。開啟指針優(yōu)化的情況下,在 arm64 架構中有 33 位?來存儲類指針

  • magic:?于調(diào)試器判斷當前對象是真的對象還是沒有初始化的空間

  • weakly_referenced:志對象是否被指向或者曾經(jīng)指向?個 ARC 的弱變量,沒有弱引?的對象可以更快釋放

  • deallocating:標志對象是否正在釋放內(nèi)存

  • has_sidetable_rc:當對象引?技術?于 10 時,則需要借?該變量存儲進位

  • extra_rc:當表示該對象的引?計數(shù)值,實際上是引?計數(shù)值減 1,
    例如,如果對象的引?計數(shù)為 10,那么 extra_rc 為 9。如果引?計數(shù)?于 10,則需要使?到下?的 has_sidetable_rc。

16238143183131.jpg
  • 用類的地址值與ISA_MASK 與就可以得出isa的信息

  • 2 根據(jù)isa里面成員變量所占字節(jié)平移一樣可以算出isa的信息操作如下圖

  • 圖一:


    16238152287173.jpg
  • 圖二


    16238161876908.jpg
  • 圖三


    16238162534830.jpg
  • 在圖一在摸儀器的中shiftcls位置在44,如圖二所示 左邊占17字節(jié) 右邊占 3字節(jié)

  • 平分方式如圖三 得出結果如圖一輸出

new與init 的關聯(lián)

+ (id)new {
    return [callAlloc(self, false/*checkNil*/) init];
}
- (id)init {
    return _objc_rootInit(self);
}
  • 從上看出new 不僅只是對對象進行初始化而且同時進行內(nèi)存分配,init只是單純的對對象進行初始化操作
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容