003-OC對象本質(zhì)

oc是面向?qū)ο蟮恼Z言理郑。對象可以看做我們對底層數(shù)據(jù)的抽象封裝。對象有自己的成員變量咨油,具備一些功能您炉,有自己所屬的類,甚至有父類役电,子類赚爵。那么oc的面相對象是怎么設計,怎么實現(xiàn)的?它的底層是由什么樣的數(shù)據(jù)結構支持的呢冀膝?

編譯

把OC編譯成c/c++是我們了解OC底層實現(xiàn)的一種方式唁奢。
簡單的clang編譯

clang -rewrite-objc main.m -o main.cpp 

有時候clang編譯會需要一些環(huán)境,sdk支持窝剖,動態(tài)特性支持

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

xcrun命令 xcode自帶的命令行工具麻掸,在clang基礎上進行了一些封裝,編譯oc代碼赐纱,更簡便一些

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 (?機)

gcc編譯器在xcode的早期版本中使用脊奋,xcode現(xiàn)在的編譯器是LLVM,采用三項插拔式設計。LLVM設計的最重要方面是疙描,使用通用代碼表示形式(IR)诚隙,它是用來在編譯器中表示代碼的形式。所以LLVM可以以任何編程語言獨立編寫前端起胰,并且可以為任意硬件架構獨立編寫后端久又。
clang 是LLVM一個子項目。負責編譯c/c++/Objective-c效五。

cpp文件中的對象

LGPerson
typedef struct objc_object LGPerson;
typedef struct {} _objc_exc_LGPerson;
#endif

struct LGPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *hobby;
};

本質(zhì)是一個objc_object類型的結構體籽孙。

objc_object
struct objc_object {
   Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
Class
typedef struct objc_class *Class;
objc_class
objc_class : objc_object {---}
id
typedef struct objc_object *id;

根據(jù)已有信息畫個圖

截屏2021-07-20 上午12.08.11.png

總結下已有信息

  • 對象本質(zhì)是一個objc_object類型的結構體
  • 對象都有一個指向objc_class結構體的指針isa
  • objc_class結構體也有一個指向objc_class的指針isa
  • id類型是objc_object *

難道我們isa指向會無限循環(huán)下嗎,如果不會那對象objc_object 和objc_class他們之間的結構是怎么樣的呢火俄?
無論如何,我們可以看到isa指針在期中扮演這關鍵的角色

isa

objc源碼

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    uintptr_t bits;

private:
    // Accessing the class requires custom ptrauth operations, so
    // force clients to go through setClass/getClass by making this
    // private.
    Class cls;

public:
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };

    bool isDeallocating() {
        return extra_rc == 0 && has_sidetable_rc == 0;
    }
    void setDeallocating() {
        extra_rc = 0;
        has_sidetable_rc = 0;
    }
#endif

    void setClass(Class cls, objc_object *obj);
    Class getClass(bool authenticated);
    Class getDecodedClass(bool authenticated);
};

如果是64位系統(tǒng)讲冠,isa_t是聯(lián)合體位域瓜客,現(xiàn)在iOS手機基本都是arm64架構。
ISA_BITFIELD是對位域的定義

x86_64
# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_HAS_CXX_DTOR_BIT 1
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;              //是否是nonpointer                           \
      uintptr_t has_assoc         : 1;    //是否有關聯(lián)對象                                     \
      uintptr_t has_cxx_dtor      : 1;     //是否有cxx析構函數(shù)                                    \
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      uintptr_t magic             : 6;       //是否已完成初始化                                  \
      uintptr_t weakly_referenced : 1;  //是否被弱引用                                       \
      uintptr_t unused            : 1;           //是否正在被釋放                              \
      uintptr_t has_sidetable_rc  : 1;     //引用計數(shù)是否存在sideTable中                                    \
      uintptr_t extra_rc          : 8    //存儲該對象的引用計數(shù)值減一后的結果, 如果夠存則存在這里竿开,不夠則存在 sidetable
arm64
# if __arm64__
// ARM64 simulators have a larger address space, so use the ARM64e
// scheme even when simulators build for ARM64-not-e.
#   if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR
#     define ISA_MASK        0x007ffffffffffff8ULL
#     define ISA_MAGIC_MASK  0x0000000000000001ULL
#     define ISA_MAGIC_VALUE 0x0000000000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 0
#     define ISA_BITFIELD                                                      \
        uintptr_t nonpointer        : 1;                                       \
        uintptr_t has_assoc         : 1;                                       \
        uintptr_t weakly_referenced : 1;                                       \
        uintptr_t shiftcls_and_sig  : 52;                                      \
        uintptr_t has_sidetable_rc  : 1;                                       \
        uintptr_t extra_rc          : 8
#     define RC_ONE   (1ULL<<56)
#     define RC_HALF  (1ULL<<7)
#   else
#     define ISA_MASK        0x0000000ffffffff8ULL
#     define ISA_MAGIC_MASK  0x000003f000000001ULL
#     define ISA_MAGIC_VALUE 0x000001a000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 1
#     define ISA_BITFIELD                                                      \
        uintptr_t nonpointer        : 1;                                       \
        uintptr_t has_assoc         : 1;                                       \
        uintptr_t has_cxx_dtor      : 1;                                       \
        uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
        uintptr_t magic             : 6;         //                              \
        uintptr_t weakly_referenced : 1;                                       \
        uintptr_t unused            : 1;                                       \
        uintptr_t has_sidetable_rc  : 1;                                       \
        uintptr_t extra_rc          : 19
#     define RC_ONE   (1ULL<<45)
#     define RC_HALF  (1ULL<<18)

位域提供了一種手段谱仪,使得可在高級語言中實現(xiàn)數(shù)據(jù)的壓縮,節(jié)省了存儲空間否彩,同時也提高了程序的效率疯攒。

上面我們isa是一個objc_class的指針。位域是我們充分利用了指針64位的內(nèi)存空間列荔,不進存儲了objc_class的指著地址敬尺,還存楚了其他對象的相關信息。

總結:

  • 對象本質(zhì)是一個objc_object類型的結構體
  • 對象都有一個指向objc_class結構體的指針isa
  • objc_class結構體也有一個指向objc_class的指針isa
  • id類型是objc_object *
  • isa是一個聯(lián)合體位域贴浙,不僅存儲了objc_class地址砂吞,還存儲了對象的其他相關信息。
  • 聯(lián)合體位域的使用崎溃,優(yōu)化了內(nèi)存也提高了部分信息的查詢效率蜻直。
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子概而,更是在濱河造成了極大的恐慌呼巷,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赎瑰,死亡現(xiàn)場離奇詭異王悍,居然都是意外死亡,警方通過查閱死者的電腦和手機乡范,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門配名,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晋辆,你說我怎么就攤上這事渠脉。” “怎么了瓶佳?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵芋膘,是天一觀的道長。 經(jīng)常有香客問我霸饲,道長为朋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任厚脉,我火速辦了婚禮习寸,結果婚禮上,老公的妹妹穿的比我還像新娘傻工。我一直安慰自己霞溪,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布中捆。 她就那樣靜靜地躺著鸯匹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪泄伪。 梳的紋絲不亂的頭發(fā)上殴蓬,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音蟋滴,去河邊找鬼染厅。 笑死,一個胖子當著我的面吹牛津函,可吹牛的內(nèi)容都是我干的糟秘。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼球散,長吁一口氣:“原來是場噩夢啊……” “哼尿赚!你這毒婦竟也來了散庶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤凌净,失蹤者是張志新(化名)和其女友劉穎悲龟,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冰寻,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡须教,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了斩芭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片轻腺。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖划乖,靈堂內(nèi)的尸體忽然破棺而出贬养,到底是詐尸還是另有隱情,我是刑警寧澤琴庵,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布误算,位于F島的核電站,受9級特大地震影響迷殿,放射性物質(zhì)發(fā)生泄漏儿礼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一庆寺、第九天 我趴在偏房一處隱蔽的房頂上張望蚊夫。 院中可真熱鬧,春花似錦懦尝、人聲如沸知纷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至埃唯,卻和暖如春撩匕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背墨叛。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工止毕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人漠趁。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓扁凛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親闯传。 傳聞我的和親對象是個殘疾皇子谨朝,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容