[TOC]
前言
- 更多OC對象相關(guān)文章請關(guān)注
01、OC-初探-對象原理-【Alloc init】
02、OC-再探-對象原理-【Alloc init】
03、OC-終探-對象原理-【Alloc init】
- 本文主要圍繞以下幾點內(nèi)容展開討論;
ISA是何時和創(chuàng)建的對象進(jìn)行綁定的?(ISA最重要的目的就是關(guān)聯(lián)了對象和類)
ISA的成員(關(guān)聯(lián)類)
類在內(nèi)存里面只有一份如何證明?
類、元類、根元類分別是如何指向的?
類的本質(zhì)是什么?
對象的本質(zhì)是什么?
ISA成員

1、根據(jù)nonpointer這個值來判斷當(dāng)前ISA指向的是純isa指針,還是bits;
- nonpointer為0: 存isa
- nonpointer為1: 不止是類對象地址,isa包含類信息,對象的引用計數(shù)等;
2、has_assoc關(guān)聯(lián)對象標(biāo)識符,0沒有,1存在;
3、has_cxx_dtor

4、shiftcls

5、magic、weakly_referenced、deall0cating、has_sidetable_rc

6、extra_rc

ISA關(guān)聯(lián)對象與類
- ISA綁定代碼

-
ISA64字節(jié)成員(x86_64和__arm64是不同的);
二進(jìn)制打印
p/t打印
八進(jìn)制打印
p/o打印
十進(jìn)制打印
p/d打印

- 如何證明ISA指針指向的是當(dāng)前alloc的類?
方案1

方案2
1、x/4gx打印對象的地址值;
2、取出第一位的ISA地址值;
3、獲取當(dāng)前創(chuàng)建對象的class
4、用當(dāng)前對象的地址值&ISA_MASK也就是0x00007ffffffffff8
5、最終得到該地址值和第一位的ISA獲取的地址值是一致的,這就驗證了ISA指向的就是當(dāng)前alloc的類;
- 代碼走向;
object_getClass-->obj->getIsa();-->ISA();-->return (Class)(isa.bits & ISA_MASK);
子網(wǎng)掩碼或者位運算的目的都是為了讓某一段內(nèi)存進(jìn)行展示

類在內(nèi)存里面只有一份如何證明?

思考:子類的ISA和父類的ISA是不是同一個ISA?
答案:肯定不是一個?。?br>

元類&根元類
類:代碼寫出來的-->內(nèi)存只有一份-->不是手動個創(chuàng)建的是系統(tǒng)自己創(chuàng)建的;
元類:系統(tǒng)編譯的-->發(fā)現(xiàn)了系統(tǒng)有這樣一個類-->系統(tǒng)也同時創(chuàng)建了編譯器;
對象ISA-->類圖解

獲取類的方法
object_getClass(object)
對象ISA-->類--類ISA>元類
解釋:對象是由類實例化創(chuàng)建的,那類也是由元類實例化創(chuàng)建的。
對象ISA-->類-->元類圖解

對象ISA-->類-->元類-->根元類圖解
對象ISA-->類-->元類-->根元類-->根元類圖解
- 第一種情況,當(dāng)創(chuàng)建的對象是NSObject時;

- 第二種情況,當(dāng)創(chuàng)建的對象是NSObject的子類時;

- 總結(jié):元類和根元類在創(chuàng)建的對象是NSObject時候可能是相同的,但是當(dāng)創(chuàng)建的對象是NSObject的子類的時候元類和根元類就不是相同的,主要是根據(jù)集成的層級管理來決定元類、根元類、根根元類的具體內(nèi)容;層級越多代表創(chuàng)建的根元類越多;
ISA走位


要點
1、圖中要分為兩個維度去看(superclass繼承鏈、ISA走位鏈)
2、繼承鏈(子類-->父類-->NSObject類-->nil找方法找不到才指向nil)
3、ISA走位鏈(對象ISA-->類-->元類-->根元類-->根元類)
4、根元類也繼承與NSObject
類的本質(zhì)
xoce快捷鍵:command + shift + 0 進(jìn)入xcode幫助模式;
官網(wǎng)地址:Type Encodings官網(wǎng)地址
類(NSObject)是什么時候創(chuàng)建的?
答案:NSObject這個基類在程序啟動的時候他就創(chuàng)建了, 在編譯器創(chuàng)建的。
類的本質(zhì)是什么?
答案:類的本質(zhì)就是oject_class,是一個結(jié)構(gòu)體!
objc_class內(nèi)部的結(jié)構(gòu)是什么樣子的?

對象的本質(zhì)
對象的本質(zhì)是什么?
答案:對象的本質(zhì)就是結(jié)構(gòu)體!
- 驗證對象的本質(zhì)是結(jié)構(gòu)體-步驟1:
1、思考,我們寫的.m文件在xcode編譯的過程中變成了什么?
2、創(chuàng)建一個空的工程, show in finder到.m文件到目錄,打開終端;執(zhí)行命令; main.m是當(dāng)前.m文件的名稱,main3.cpp是即將生成文件的名稱;
$ clang -x objective-c -rewrite-objc main.m -o main3.cpp
3、打開main3.cpp文件;

4、找到該對象名對應(yīng)的結(jié)構(gòu)體截圖;


疑問:默認(rèn)的成員里面的struct NSObject_IMPL 里面有什么成員?
回答:struct NSObject_IMPL 里面的成員變量是 isa(見下圖)

5、結(jié)構(gòu)體中的NSObject_IVARS成員是繼承來的;其他的成員變量或者屬性是我們聲明出來的;
成員變量和屬性在編譯的過程當(dāng)中有什么區(qū)別?
答案: 成員變量沒有set、get方法,屬性有set、get的方法;
結(jié)論: 屬性 = 成員變量 + get方法 + set方法;

備注:如果在使用終端clang命令報錯,報錯內(nèi)容是"缺少UIKit庫的問題,請執(zhí)行下面指令到控制臺即可"

總結(jié)
ISA是何時和創(chuàng)建的對象進(jìn)行綁定的?
答案:ISA最重要的目的就是關(guān)聯(lián)了對象和類 isa <-> cls;
如何獲取一個類的父類?
步驟1
object_getClass方法即可;
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
步驟2
getIsa方法即可;
objc_object::getIsa()
{
if (!isTaggedPointer()) return ISA();
uintptr_t ptr = (uintptr_t)this;
if (isExtTaggedPointer()) {
uintptr_t slot =
(ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
return objc_tag_ext_classes[slot];
} else {
uintptr_t slot =
(ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
return objc_tag_classes[slot];
}
}
步驟3
ISA()方法即可;
objc_object::ISA()
{
assert(!isTaggedPointer());
#if SUPPORT_INDEXED_ISA
if (isa.nonpointer) {
uintptr_t slot = isa.indexcls;
return classForIndex((unsigned)slot);
}
return (Class)isa.bits;
#else
return (Class)(isa.bits & ISA_MASK);
#endif
}
-
關(guān)鍵代碼
return (Class)(isa.bits & ISA_MASK);
isa.bits就是當(dāng)前isa指向的地址值,ISA_MASK就是掩碼,這個位置可以看本文ISA關(guān)聯(lián)對象與類的節(jié)點;
ISA指向
對象ISA-->類-->元類-->根元類-->根元類
class的繼承管理
子類subclass-->父類superclass-->NSObject-->nil
根元類的父類是NSObject
類的本質(zhì)是什么?
結(jié)構(gòu)體;
對象的本質(zhì)是什么?
結(jié)構(gòu)體;