咱們從iOS底層原理之—dyld與objc的關聯中知道dyld關聯objc
時,經過_read_images
函數中的readClass
函數來讀取類的信息並將類關聯起來,咱們本文主要來探討類的加載。markdown
_read_images
函數因爲咱們探究的是類的加載,且在iOS底層原理之—dyld與objc的關聯中咱們已經主要分析了下_read_images
函數的做用,所以咱們主要看_read_images
函數中有關的部分代碼,上代碼app
// Discover classes. Fix up unresolved future classes. Mark bundle classes.
bool hasDyldRoots = dyld_shared_cache_some_image_overridden();
for (EACH_HEADER) {
if (! mustReadClasses(hi, hasDyldRoots)) {
// Image is sufficiently optimized that we need not call readClass()
continue;
}
classref_t const *classlist = _getObjc2ClassList(hi, &count);
bool headerIsBundle = hi->isBundle();
bool headerIsPreoptimized = hi->hasPreoptimizedClasses();
for (i = 0; i < count; i++) {
Class cls = (Class)classlist[i];
Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
if (newCls != cls && newCls) {
// Class was moved but not deleted. Currently this occurs
// only when the new class resolved a future class.
// Non-lazily realize the class below.
resolvedFutureClasses = (Class *)
realloc(resolvedFutureClasses,
(resolvedFutureClassCount+1) * sizeof(Class));
resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
}
}
}
ts.log("IMAGE TIMES: discover classes");
複製代碼
readClass
部分代碼readClass
以前cls分析在沒有調用readClass
時,咱們讀取cls信息從上圖中咱們發現此時cls只是一串地址函數
readClass
以後cls分析調用readClass
以後,咱們讀取cls信息從上圖中咱們得知cls已經由一串地址變成了LGPerson類。所以咱們得出必定是readClsss
函數作了什麼,咱們來分析下readClsss
函數。post
readClsss
函數分析Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
const char *mangledName = cls->mangledName();
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
auto kc_ro = (const class_ro_t *)cls->data();
printf("readClass: 這個是我要研究的 %s \n",LGPersonName);
}
if (missingWeakSuperclass(cls)) {
// No superclass (probably weak-linked).
// Disavow any knowledge of this subclass.
if (PrintConnecting) {
_objc_inform("CLASS: IGNORING class '%s' with "
"missing weak-linked superclass",
cls->nameForLogging());
}
addRemappedClass(cls, nil);
cls->superclass = nil;
return nil;
}
cls->fixupBackwardDeployingStableSwift();
Class replacing = nil;
if (Class newCls = popFutureNamedClass(mangledName)) {
// This name was previously allocated as a future class.
// Copy objc_class to future class's struct.
// Preserve future's rw data block.
if (newCls->isAnySwift()) {
_objc_fatal("Can't complete future class request for '%s' "
"because the real class is too big.",
cls->nameForLogging());
}
class_rw_t *rw = newCls->data();
const class_ro_t *old_ro = rw->ro();
memcpy(newCls, cls, sizeof(objc_class));
rw->set_ro((class_ro_t *)newCls->data());
newCls->setData(rw);
freeIfMutable((char *)old_ro->name);
free((void *)old_ro);
addRemappedClass(cls, newCls);
replacing = cls;
cls = newCls;
}
if (headerIsPreoptimized && !replacing) {
// class list built in shared cache
// fixme strict assert doesn't work because of duplicates
// ASSERT(cls == getClass(name));
ASSERT(getClassExceptSomeSwift(mangledName));
} else {
addNamedClass(cls, mangledName, replacing);
addClassTableEntry(cls);
}
// for future reference: shared cache never contains MH_BUNDLEs
if (headerIsBundle) {
cls->data()->flags |= RO_FROM_BUNDLE;
cls->ISA()->data()->flags |= RO_FROM_BUNDLE;
}
return cls;
}
複製代碼
源碼中爲了更好的區別出LGPerson
,特地添加了判斷LGPerson
類型的代碼ui
經過代碼調試,最終執行了addNamedClsss
函數在執行addNamedClsss
函數以前打印cls依然是一串地址。當執行完addNamedClsss
函數時,打印cls發現指向了LGPerson
所以咱們得出addNamedClsss
對cls進行了指向操做。this
addNamedClsss
函數懶加載類
:推遲到第一次消息發送的時候才加載的類稱爲懶加載類
;非懶加載類
:在map_images
函數執行_read_images
函數時就加載的類,稱爲非懶加載類
+load
函數,則就是非懶加載類
,沒有實現就是懶加載類
懶加載類
分析對於LGPerson類不實現+load
函數,咱們從前面分析知道_read_images
中有處理非懶加載類
代碼,咱們打上斷點以及打印,如圖因爲LGPerson沒有實現+load
函數,因此是懶加載類,所以沒有進入咱們的斷點。然而LGPerson
類在何時加載了呢?咱們研究 非懶加載類
的代碼發現,實現了realizeClassWithoutSwift
函數,所以咱們看懶加載類
會不會進入這個函數。spa
realizeClassWithoutSwift
從這裏咱們驗證了懶加載類
的類的加載延遲到第一次消息發送
ssr
非懶加載類
分析咱們讓LGPerson
實現+load
函數,裏面什麼也不用作,如圖此時看_read_images
中有關非懶加載類
的處理此時咱們看到進入了咱們原先的斷點中,且也執行了realizeClassWithoutSwift
函數3d
realizeClassWithoutSwift
函數重點代碼分析 調試