咱們的Xcode其實很強大,集成了不少牛逼的工具,clang就是其中之一,咱們可使用如下的命令對.m文件進行編譯咱們就能夠看到咱們的OC 編譯到底層的C或者C++究竟是怎麼樣的c++
我這裏的例子是使用的是main.m 文件,各位能夠根據具體SDK的文件路徑和須要編譯的文件去編譯研究
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk main.m //模擬器的使用命令
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk main.m //真機的使用命令
複製代碼
咱們編譯完看到的就是一個C++的結構體,沒錯就是一個objec_class的結構體,他的結構體長成這個樣子: objective-c
固然下面還有不少的函數,太長了,不浪費地方了。咱們發現有些有意思的問題:在上面我有說到對象在實例化時返回的就是一個isa,並且就幹了一件事情,就是把咱們實例化出來的對象跟類進行綁定。那麼isa就是是個啥玩意?且看如下分解:數組
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
};
複製代碼
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \表示是否對 isa 指針開啓指針優化
uintptr_t has_assoc : 1; \是否有關聯對象
uintptr_t has_cxx_dtor : 1; \否有 C++ 或者 Objc 的析構器
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \存儲類指針的值
uintptr_t magic : 6; \用於調試器判斷當前對象是真的對象仍是沒有初始化的空間
uintptr_t weakly_referenced : 1; \是否被指向或者曾經指向一個 ARC 的弱變量
uintptr_t deallocating : 1; \是否正在釋放
uintptr_t has_sidetable_rc : 1; \當對象引用技術大於 10 時,則須要借用該變量存儲進位
uintptr_t extra_rc : 19\當表示該對象的引用計數值,其實是引用計數值減 1,當大於10時須要借用上面的標誌位
複製代碼
這是一個宏定義的位域,後面的數字表示佔有的位數。其實就是對isa進行了優化,把一個8字節的空間進行了高效使用,從而存儲了更多的東西,如剛剛的cls 就存儲在shiftcls中。緩存
相信有不少人已經有所瞭解,可是說到isa,我仍是介紹下走位bash
字面意思就是緩存,事實上Runtime進行消息查找的時候若是每次查完就直接扔了很浪費,哪些常常用的或者最近查找過的方法會進行緩存,這樣就提升了方法調用的效率。具體介紹能夠參考我以前寫過的關於cache_t的分析的文章 https://juejin.im/post/5e1469f6e51d4541657776b4
app
不知道咱們是否是很好奇,既然對象實例化以後啥都沒有那麼我寫的那些屬性、方法都在哪呢?難道在類裏面嗎? 還真是,不過這個類是相對的,類是對象的類,元類是類的類,以此類推。bits裏面就存了對象的屬性、實例化方法(注意是實例化方法,類方法在元類的bits裏面)ide
咱們看到了bits.data()返回的是一個class_rw_t *結構體指針,說明了這個bits裏面存的就是這個結構體數據。函數
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
複製代碼
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
method_list_t *baseMethods() const {
return baseMethodList;
}
};
複製代碼
咱們來先自定義一個類,配置好objc的源碼,用LLDB調試看看內存中的數據工具
獲取bits中的數據 post
ro中的數據
讀屬性,nickName 已經在數組中的第一個,總數也是一個(咱們的類中也只寫了一個)。
讀方法,屬性對應的set、get方法,咱們本身定義的一個實例化方以及一個c++的函數
在這些底層的研究過程當中,思考蘋果開發工程師的開發思路和設計思想是一件很享受的事情,弄清楚他們怎樣作到讓這個代碼的效率如此之高對本身的開發水平提升有很好地幫助,用C++ 寫過遊戲的朋友估計體驗比較深入,遊戲全部的都是本身實現,除了場景以及渲染用到的遊戲引擎。
有興趣一塊兒交流的朋友,能夠加 QQ:578200388