iOS底層原理_03:OC對象原理(下)

第三節(jié)課 OC對象原理(下)

全篇開始之前我們想一個問題裹唆,研究了這么久對象,究竟什么是對象呢?舍咖?

對象本質以及拓展

Clang

探索對象的本質前,我們先了解一個編譯器:clang
Clang是一個C語言锉桑、C++排霉、OC語言的輕量級編譯器。源代碼發(fā)布于BSD協(xié)議下民轴。Clang將支持其普通lambda表達式攻柠、返回類型的簡化處理以及更好的處理constexpr關鍵字。

clang是一個由Apple主導編寫后裸,基于LLVM的C/C++/OC的編譯器

探索本質

1瑰钮、在main中自定義一個類LGPerson,有一個屬性name

@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
@end

@implementation LGPerson
@end

2微驶、通過終端浪谴,利用clangmain.m編譯成 main.cpp

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

3、打開編譯好的main.cpp因苹,找到LGPerson的定義苟耻,發(fā)現(xiàn)LGPerson在底層會被編譯成struct 結構體

03-對象的本質是結構體.png

我們可以看到,這是一個結構體扶檐,里面嵌套了一個結構體梁呈,結構體能夠繼承嘛?其實是可以的蘸秘,但是是屬于偽繼承官卡,偽繼承的方式是直接將NSObject結構體定義為LGPerson中的第一個屬性,意味著LGPerson擁有NSObject中的所有成員變量醋虏。

LGPerson_IMPL中的第一個屬性寻咒,其實就是isa,是繼承自NSObject颈嚼,

03-IVARS.png

通過上圖我們可以看到成員變量是Class isa毛秘。通常叫isa叫做isa指針,那么這里的Class應該是個指針類型阻课,在main.cpp文件中全局搜索*Class叫挟。代碼如下

03-class.png

LGPerson的類型是objc_object,在OC層面 我們的LGPerson是繼承NSObject限煞,其實在下層真正的實現(xiàn)就是objc_object抹恳。

03-objc_object.png

對象的本質拓展

在剛才看class的過程中,還發(fā)現(xiàn)了兩個東西


03-id署驻、sel.png

熟悉的idSEL奋献。常用的id原來是一個objc_object結構體指針健霹,這就解釋了id修飾變量和作為返回值的時候為什么不加*,下面的SEL也是結構體指針這個也是之前不知道的呢瓶蚂,就稍微了解下吧~

在稍下面一點我們看到一些奇奇怪怪的一些東西

03-方法的get糖埋、set.png

這其實就是我們的Get方法Set方法,但是參數(shù)部分呢窃这?我們可在OC中沒有看到瞳别,這其實就 是我們的隱藏參數(shù)。
這個Get方法中的參數(shù)self+OBJC_IVAR_$_LGPerson$_name這一步就是我們之前講過的杭攻,要獲取一個類的對象的地址祟敛,是通過獲取類的首地址+對象的偏移量的方法來最終取得對象的。

小結

所以從上述探索過程中可以得出:

  • OC對象的本質其實就是結構體
  • LGPerson中的isa繼承NSObject中的isa

聯(lián)合體位域拓展補充

位域(位段)

位域:在C語言中允許在一個結構體中以位為單位來指定其成員所占內存長度朴上,這種以位為單元的成員稱為位域。

struct HZMCar1 {
    BOOL front; // 0 1
    BOOL back;
    BOOL left;
    BOOL right;
};
struct HZMCar1 car1;
NSLog(@"%ld",sizeof(car1));
<--打印輸出-->
4

在開發(fā)當中遇到這種情況卒煞,其實BOOL就只有兩種情況痪宰,但是卻使用了4個字節(jié)32位,其實我們只用4位就可以了畔裕,這樣我們就只使用了1字節(jié)衣撬,還有3字節(jié)其實是浪費的。接下來我們進行改進一下

struct HZMCar2 {
    BOOL front: 1;
    BOOL back : 1;
    BOOL left : 1;
    BOOL right: 1;
};
struct HZMCar2 car2;
NSLog(@"%ld",sizeof(car2));
<--打印輸出-->
1

其實就是指定對象所占內存長度

聯(lián)合體(共用體)

struct LGStudent {
    char        *name;
    int         age;
    double      height ;
};

union LGStudent2 {
    char        *name;
    int         age;
    double      height ;
};
struct LGStudent   student;
student.name = "HZM";
student.age  = 18;

union LGStudent2    student2;
student2.name = "HZM";
student2.age  = 18;
NSLog(@"%ld-%ld",sizeof(student),sizeof(student2));
<--打印輸出-->
24-8

首先我們能觀察到扮饶,同樣的成員變量具练,內存大小天差地別,這是為什么呢甜无?我們來通過斷點查看下扛点。

03-聯(lián)合體.png

可以看到聯(lián)合的成員變量在未賦值的情況下是一塊臟數(shù)據、臟內存岂丘,當?shù)诙€變量被賦值的時候又將第一個變量清理了陵究,所以聯(lián)合體的各種變量互斥,每次只能賦值一個奥帘,這樣就可以接受大幅空間铜邮,這也就是我們之前看到的為什么聯(lián)合體的內存大小比較小的原因。

小結:

位域和聯(lián)合體對比
位域:優(yōu)點是所有變量可以共存寨蹋,缺點是內存空間粗放松蒜,不管用不用,都分配
聯(lián)合體:優(yōu)點是內存更精細靈活已旧,節(jié)省空間秸苗,缺點是各種變量互斥

isa的類型 isa_t

以下是isa指針的類型isa_t的定義,從定義中可以看出是通過聯(lián)合體(union)定義的运褪。

union isa_t { //聯(lián)合體
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    //提供了cls 和 bits 难述,兩者是互斥關系
    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};  

isa_t類型使用聯(lián)合體的原因也是基于內存優(yōu)化的考慮萤晴,這里的內存優(yōu)化是指在isa指針中通過char + 位域(即二進制中每一位均可表示不同的信息)的原理實現(xiàn)。通常來說胁后,isa指針占用的內存大小是8字節(jié)店读,即64位,已經足夠存儲很多的信息了攀芯,這樣可以極大的節(jié)省內存屯断,以提高性能
從isa_t的定義中可以看出:

  • 提供了兩個成員,clsbits侣诺,由聯(lián)合體的定義所知殖演,這兩個成員是互斥的,也就意味著年鸳,當初始化isa指針時趴久,只有一個變量有值

    • 通過cls初始化,bits無默認值
    • 通過bits初始化搔确,cls有默認值
  • 還提供了一個結構體定義的位域彼棍,用于存儲類信息及其他信息,結構體的成員ISA_BITFIELD膳算,這是一個宏定義座硕,有兩個版本 __arm64__(對應ios 移動端) 和 __x86_64__(對應macOS),以下是它們的一些宏定義涕蜂,如下圖

    03-ISA_BITFIELD.png

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位用來存儲類指針您机,x86_64中占 44
magic:用于調試器判斷當前對象是真的對象還是沒有初始化的空間
weakly_referenced:標志對象是否被指向或者曾經指向一個ARC的弱變量
沒有弱引用的對象可以更快釋放年局。
deallocating:標志對象是否正在釋放內存
has_sidetable_rc:當對象引用計數(shù)大于 10 時际看,則需要借用該變量存儲進位
extra_rc:當表示該對象的引用計數(shù)值,實際上是引用計數(shù)值減 1
例如矢否,如果對象的引用計數(shù)為 10仲闽,那么 extra_rc9。如果引用計數(shù)大于 10僵朗, 則需要使用到上面的 has_sidetable_rc赖欣。

03-isa存儲情況.png

ISA_MASK

ISA_MASK是一個宏,一個掩碼屑彻。__x86_64__ 的值等于 0x00007ffffffffff8ULL__arm64__ 的值等于0x0000000ffffffff8ULL顶吮。通過x/4g p獲取到的首位地址就是isa的值是0x001d800100008275社牲,驗證下0x001d800100008275&0x00007ffffffffff8ULL結果

03-MASK.png

對象通過 isa & 掩碼 得到類的信息

isa的位運算

通過上面的學習我們已經知道了isashiftcls是用來存儲類指針,所以我們降妖獲取類指針其實也可以通過位運算獲取shiftcls的最終值悴了。

03-位運算.png

通過上圖我們發(fā)現(xiàn)搏恤,其實我們要獲取的shiftcls正好在中間,左邊有3位湃交,右邊有28位熟空,那我們如果要獲取的話就可以將shiftcls整體向左移3位,將多余部分擠出去搞莺,向右移20位息罗,將左邊的多余部分擠出去,最后左移17位恢復原位才沧,這個時候剩下的不就是我們需要的shiftcls了迈喉。我們來驗證下

03-驗證位運算.png

可以看到位運算結束后的結果與我們輸出的class相同。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末糜工,一起剝皮案震驚了整個濱河市弊添,隨后出現(xiàn)的幾起案子录淡,更是在濱河造成了極大的恐慌捌木,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫉戚,死亡現(xiàn)場離奇詭異刨裆,居然都是意外死亡,警方通過查閱死者的電腦和手機彬檀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門帆啃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窍帝,你說我怎么就攤上這事努潘。” “怎么了坤学?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵疯坤,是天一觀的道長。 經常有香客問我深浮,道長压怠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任飞苇,我火速辦了婚禮菌瘫,結果婚禮上蜗顽,老公的妹妹穿的比我還像新娘。我一直安慰自己雨让,他們只是感情好雇盖,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宫患,像睡著了一般刊懈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上娃闲,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天虚汛,我揣著相機與錄音,去河邊找鬼皇帮。 笑死卷哩,一個胖子當著我的面吹牛,可吹牛的內容都是我干的属拾。 我是一名探鬼主播将谊,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼渐白!你這毒婦竟也來了尊浓?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤纯衍,失蹤者是張志新(化名)和其女友劉穎栋齿,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體襟诸,經...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡瓦堵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了歌亲。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菇用。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖陷揪,靈堂內的尸體忽然破棺而出惋鸥,到底是詐尸還是另有隱情,我是刑警寧澤悍缠,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布卦绣,位于F島的核電站,受9級特大地震影響扮休,放射性物質發(fā)生泄漏迎卤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一玷坠、第九天 我趴在偏房一處隱蔽的房頂上張望蜗搔。 院中可真熱鬧劲藐,春花似錦、人聲如沸樟凄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缝龄。三九已至汰现,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叔壤,已是汗流浹背瞎饲。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留炼绘,地道東北人嗅战。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像俺亮,于是被迫代替她去往敵國和親驮捍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內容