[TOC]
前言
- 本文主要圍繞以下幾點內容展開討論;
ISA是何時和創建的對象進行綁定的?(ISA最重要的目的就是關聯了對象和類)
ISA的成員(關聯類)
類在內存里面只有一份如何證明?
類、元類、根元類分別是如何指向的?
類的本質是什么?
對象的本質是什么?
ISA成員
1、根據nonpointer
這個值來判斷當前ISA指向的是純isa指針,還是bits
;
- nonpointer為0: 存isa
- nonpointer為1: 不止是類對象地址,isa包含類信息,對象的引用計數等;
2、has_assoc
關聯對象標識符,0沒有,1存在;
3、has_cxx_dtor
4、shiftcls
5、magic
、weakly_referenced
、deall0cating
、has_sidetable_rc
6、extra_rc
ISA關聯對象與類
- ISA綁定代碼
-
ISA
64字節成員(x86_64和__arm64是不同的);
二進制打印
p/t
打印
八進制打印
p/o
打印
十進制打印
p/d
打印
- 如何證明ISA指針指向的是當前alloc的類?
方案1
方案2
1、x/4gx
打印對象的地址值;
2、取出第一位的ISA地址值;
3、獲取當前創建對象的class
4、用當前對象的地址值&ISA_MASK也就是0x00007ffffffffff8
5、最終得到該地址值和第一位的ISA獲取的地址值是一致的,這就驗證了ISA指向的就是當前alloc的類;
- 代碼走向;
object_getClass
-->obj->getIsa();
-->ISA();
-->return (Class)(isa.bits & ISA_MASK);
類在內存里面只有一份如何證明?
思考
:子類的ISA和父類的ISA是不是同一個ISA?
答案
:肯定不是一個啊!
元類&根元類
類
:代碼寫出來的-->內存只有一份-->不是手動個創建的是系統自己創建的;
元類
:系統編譯的-->發現了系統有這樣一個類-->系統也同時創建了編譯器;
對象ISA
-->類
圖解
獲取類的方法
object_getClass(object)
對象ISA
-->類
--類ISA
>元類
解釋:對象是由類實例化創建的,那類也是由元類實例化創建的。
對象ISA
-->類
-->元類
圖解
對象ISA
-->類
-->元類
-->根元類
圖解
對象ISA
-->類
-->元類
-->根元類
-->根元類
圖解
- 第一種情況,當創建的對象是NSObject時;
- 第二種情況,當創建的對象是NSObject的子類時;
- 總結:元類和根元類在創建的對象是NSObject時候可能是相同的,但是當創建的對象是NSObject的子類的時候元類和根元類就不是相同的,主要是根據集成的層級管理來決定元類、根元類、根根元類的具體內容;層級越多代表創建的根元類越多;
ISA走位
要點
1、圖中要分為兩個維度去看(superclass繼承鏈、ISA走位鏈)
2、繼承鏈
(子類-->父類-->NSObject類-->nil
找方法找不到才指向nil)
3、ISA走位鏈
(對象ISA
-->類
-->元類
-->根元類
-->根元類
)
4、根元類也繼承與NSObject
類的本質
xoce快捷鍵:command
+ shift
+ 0
進入xcode
幫助模式;
官網地址:Type Encodings官網地址
類(NSObject)是什么時候創建的?
答案:NSObject
這個基類在程序啟動的時候他就創建了, 在編譯器創建的。
類的本質是什么?
答案:類的本質就是oject_class,是一個結構體!
objc_class內部的結構是什么樣子的?
對象的本質
對象的本質是什么?
答案:
對象的本質就是結構體!
- 驗證對象的本質是結構體-步驟1:
1、思考,我們寫的.m文件在xcode編譯的過程中變成了什么?
2、創建一個空的工程, show in finder到.m文件到目錄,打開終端;執行命令; main.m是當前.m文件的名稱,main3.cpp是即將生成文件的名稱;
$ clang -x objective-c -rewrite-objc main.m -o main3.cpp
3、打開main3.cpp文件;
4、找到該對象名對應的結構體截圖;
疑問:默認的成員里面的struct NSObject_IMPL 里面有什么成員?
回答:
struct NSObject_IMPL 里面的成員變量是 isa
(見下圖)
5、結構體中的NSObject_IVARS成員是繼承來的;其他的成員變量或者屬性是我們聲明出來的;
成員變量和屬性在編譯的過程當中有什么區別?
答案:
成員變量沒有set、get方法,屬性有set、get的方法;
結論:
屬性 = 成員變量 + get方法 + set方法;
備注:如果在使用終端clang命令報錯,報錯內容是"缺少UIKit庫的問題,請執行下面指令到控制臺即可"
總結
ISA是何時和創建的對象進行綁定的?
答案:ISA最重要的目的就是關聯了對象和類 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
}
-
關鍵代碼
return (Class)(isa.bits & ISA_MASK);
isa.bits就是當前isa指向的地址值,ISA_MASK就是掩碼,這個位置可以看本文ISA關聯對象與類
的節點;
ISA指向
對象ISA
-->類
-->元類
-->根元類
-->根元類
class的繼承管理
子類subclass
-->父類superclass
-->NSObject
-->nil
根元類
的父類
是NSObject
類的本質是什么?
結構體;
對象的本質是什么?
結構體;