objc源碼中NSObject如何進行初始化
+ alloc 和 - init 這一對我們在 iOS 開發中每天都要用到的初始化方法一直困擾著我, 于是筆者仔細研究了一下 objc 源碼中 NSObject 如何進行初始化。
在具體分析對象的初始化過程之前,我想先放出結論,以免文章中的細枝末節對讀者的理解有所影響;整個對象的初始化過程其實只是 為一個分配內存空間,并且初始化 isa_t 結構體的過程。
alloc 方法分析
先來看一下 + alloc 方法的調用棧(在調用棧中省略了很多不必要的方法的調用):
id _objc_rootAlloc(Class cls)
└── static id callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
└── id class_createInstance(Class cls, size_t extraBytes)
└── id _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, bool cxxConstruct, size_t *outAllocatedSize)
├── size_t instanceSize(size_t extraBytes)
├── void *calloc(size_t, size_t) └── inline void objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
這個調用棧中的方法涉及了多個文件中的代碼,在下面的章節中會對調用的方法逐步進行分析,如果這個調用棧讓你覺得很頭疼,也不是什么問題。
alloc 的實現
+ (id)alloc {
return _objc_rootAlloc(self);
}
alloc 方法的實現真的是非常的簡單, 它直接調用了另一個私有方法 id _objc_rootAlloc(Class cls)
id _objc_rootAlloc(Class cls) {
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
這就是上帝類 NSObject 對 callAlloc 的實現,我們省略了非常多的代碼,展示了最常見的執行路徑:
static id callAlloc(Class cls, bool checkNil, bool allocWithZone=false) {
id obj = class_createInstance(cls, 0);
return obj;
}
id class_createInstance(Class cls, size_t extraBytes) {
return _class_createInstanceFromZone(cls, extraBytes, nil);
}
對象初始化中最重要的操作都在 _class_createInstanceFromZone 方法中執行:
static id _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, bool cxxConstruct = true, size_t *outAllocatedSize = nil) {
size_t size = cls-》instanceSize(extraBytes);
id obj = (id)calloc(1, size);
if (!obj) return nil;
obj-》initInstanceIsa(cls, hasCxxDtor);
return obj;
}
對象的大小
在使用 calloc 為對象分配一塊內存空間之前,我們要先獲取對象在內存的大小:
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
if (size 《 16) size = 16;
return size;
}
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
uint32_t unalignedInstanceSize() {
assert(isRealized());
return data()-》ro-》instanceSize;
}
實例大小 instanceSize 會存儲在類的 isa_t 結構體中,然后經過對齊最后返回。
Core Foundation 需要所有的對象的大小都必須大于或等于 16 字節。
在獲取對象大小之后,直接調用 calloc 函數就可以為對象分配內存空間了。
isa 的初始化
在對象的初始化過程中除了使用 calloc 來分配內存之外,還需要根據類初始化 isa_t 結構體:
inline void objc_object::initIsa(Class cls, bool indexed, bool hasCxxDtor) {
if (!indexed) {
isa.cls = cls;
} else {
isa.bits = ISA_MAGIC_VALUE;
isa.has_cxx_dtor = hasCxxDtor;
isa.shiftcls = (uintptr_t)cls 》》 3;
}
}
上面的代碼只是對 isa_t 結構體進行初始化而已:
union isa_t { isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
struct {
uintptr_t indexed : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 44;
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 8;
};
};
init 方法
NSObject 的 - init 方法只是調用了 _objc_rootInit 并返回了當前對象:
- (id)init {
return _objc_rootInit(self);
}
id _objc_rootInit(id obj) {
return obj;
}
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%
下載地址
objc源碼中NSObject如何進行初始化下載
相關電子資料下載
- iOS17.1可能明天發布,iOS17.1主要修復哪些問題? 377
- 華為全新鴻蒙蓄勢待發 僅支持鴻蒙內核和鴻蒙系統應用 719
- 蘋果手機系統iOS 17遭用戶質疑 731
- iPhone12輻射超標?蘋果推送iOS 17.1解決此事 750
- 傳華為囤積零部件 目標明年智能手機出貨7000萬部;消息稱 MiOS 僅限國內,小米 28208
- 蘋果推送iOS17.0.3,解決iPhone15Pro系列存在機身過熱 216
- Testin云測兼容和真機服務平臺中上線iPhone 15系列手機 208
- 利爾達推出搭載HooRiiOS的Matter模組 145
- 運放參數解析:輸入偏置電流(Ibias)和失調電流(Ios) 128
- 昆侖太科發布支持國產飛騰騰銳D2000芯片的開源BIOS固件版本 448