本文介紹類的信息加載。
前面篇章中簡(jiǎn)單分析了dyld的流程,再到dylibsystem調(diào)用_objc_init,整個(gè)流程的目的是為了將類的信息加載到內(nèi)存中。包括其屬性、方法、協(xié)議、分類等,將代碼編譯,編成MachO的格式,再寫(xiě)入到內(nèi)存。
Mach-O為Mach object文件格式的縮寫(xiě),它是mac以及iOS上一種用于可執(zhí)行文件、目標(biāo)代碼、動(dòng)態(tài)庫(kù)的文件格式。常見(jiàn):目標(biāo)文件:
.o;庫(kù)文件.a,.dylib,Framework;可執(zhí)行文件:dyld,.dsym
_read_images
先介紹讀取鏡像文件,它存在于objc工程中的objc-runtime-new.mm中,代碼量非常多,但我們從其中得到重要的信息,并對(duì)我們關(guān)心的類相關(guān)處理做分析。
1、條件控制進(jìn)行的一次加載
2、修復(fù)預(yù)編譯階段的@selector的混亂問(wèn)題
3、錯(cuò)誤混亂的類處理
4、修復(fù)重映射一些沒(méi)有被鏡像文件加載進(jìn)來(lái)的類
5、修復(fù)一些消息
6、當(dāng)類里面有協(xié)議時(shí):readProtocol 讀取協(xié)議
7、修復(fù)沒(méi)有被加載的協(xié)議
8、分類處理
9、類的加載處理
10、沒(méi)有被處理的類,優(yōu)化那些被侵犯的類
條件控制進(jìn)行的一次加載
if (!doneOnce) {
// namedClasses
// Preoptimized classes don't go in this table.
// 4/3 is NXMapTable's load factor
int namedClassesSize =
(isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
//創(chuàng)建哈希表:方便快速對(duì)類進(jìn)行查找
gdb_objc_realized_classes =
NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
ts.log("IMAGE TIMES: first time tasks");
}
在doneOnce流程中通過(guò)NXCreateMapTable創(chuàng)建表,存放類信息,即創(chuàng)建一張類的哈希表gdb_objc_realized_classes,其目的是為了類查找方便、快捷。
修復(fù)預(yù)編譯階段的@selector的混亂問(wèn)題
從從 _getObjc2SelectorRefs獲得MachO中的靜態(tài)段__objc_selrefs,然后遍歷獲取sel,修復(fù)sel不一致問(wèn)題。
// Fix up @selector references
static size_t UnfixedSelectors;
{
mutex_locker_t lock(selLock);
for (EACH_HEADER) {
if (hi->hasPreoptimizedSelectors()) continue;
bool isBundle = hi->isBundle();
//從 _getObjc2SelectorRefs獲得MachO中的靜態(tài)段__objc_selrefs
SEL *sels = _getObjc2SelectorRefs(hi, &count);
UnfixedSelectors += count;
// 對(duì)列表進(jìn)行遍歷
for (i = 0; i < count; i++) {
// 獲取sel字符
const char *name = sel_cname(sels[i]);
// 透過(guò)name獲取sel,該sel類型是:(SEL)*it.first,取了地址
SEL sel = sel_registerNameNoLock(name, isBundle);
// 如果名字可能相同,但地址不同,就修復(fù)不相同的的sel
if (sels[i] != sel) {
sels[i] = sel;
}
}
}
}
獲取MachO中的靜態(tài)段名
// function name content type section name
GETSECT(_getObjc2SelectorRefs, SEL, "__objc_selrefs");
GETSECT(_getObjc2MessageRefs, message_ref_t, "__objc_msgrefs");
GETSECT(_getObjc2ClassRefs, Class, "__objc_classrefs");
GETSECT(_getObjc2SuperRefs, Class, "__objc_superrefs");
GETSECT(_getObjc2ClassList, classref_t const, "__objc_classlist");
GETSECT(_getObjc2NonlazyClassList, classref_t const, "__objc_nlclslist");
GETSECT(_getObjc2CategoryList, category_t * const, "__objc_catlist");
GETSECT(_getObjc2CategoryList2, category_t * const, "__objc_catlist2");
GETSECT(_getObjc2NonlazyCategoryList, category_t * const, "__objc_nlcatlist");
GETSECT(_getObjc2ProtocolList, protocol_t * const, "__objc_protolist");
GETSECT(_getObjc2ProtocolRefs, protocol_t *, "__objc_protorefs");
GETSECT(getLibobjcInitializers, UnsignedInitializer, "__objc_init_func");
錯(cuò)誤混亂的類處理
// 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)) {
// 如果鏡像已經(jīng)優(yōu)化,無(wú)需調(diào)用readclass()
continue;
}
//獲取編譯后類列表中的所有類,從Mach-O獲取__objc_classlist,獲得一個(gè)classref_t類型的指針
classref_t const *classlist = _getObjc2ClassList(hi, &count);
bool headerIsBundle = hi->isBundle();
bool headerIsPreoptimized = hi->hasPreoptimizedClasses();
for (i = 0; i < count; i++) {
// 從列表中得到cls,但只有地址
Class cls = (Class)classlist[I];
// ** 讀取類,使得cls獲取的值有對(duì)應(yīng)的name。此時(shí)cls包含了地址+類的name
Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
// 這是懶加載流程下的判斷,由于初始化所有懶加載的類需要的內(nèi)存空間,此時(shí)懶加載類未初始化,類信息此時(shí)沒(méi)有,不執(zhí)行該邏輯。非懶加載則執(zhí)行
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.
// 將懶加載的類添加到數(shù)組中
resolvedFutureClasses = (Class *)
realloc(resolvedFutureClasses,
(resolvedFutureClassCount+1) * sizeof(Class));
resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
}
}
}
ts.log("IMAGE TIMES: discover classes");
readClass讀取類
cls在readClass被調(diào)用之前只是從表中獲取到了地址,未獲取name
/* 讀取閱讀類
* 讀取由編譯器編寫(xiě)的類和元類
* 返回新的類指針。這可能是:
* - cls
* - 零 (cls 缺少弱鏈接超類)
* - 其他內(nèi)容(此類的空間由將來(lái)的類保留)
* 請(qǐng)注意,此功能執(zhí)行的所有工作都由
* 必讀類 () 。在不更新該函數(shù)之前,請(qǐng)勿更改
* 鎖定:由用戶或map_images獲取的objc_readClassPair
*/
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
// 若當(dāng)前類沒(méi)有父類,就返回nil
const char *mangledName = cls->mangledName();
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;
// 判斷是不是未來(lái)處理的類
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());
}
// 讀取newCls的data,從ro復(fù)制一份data,賦值給rw
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;
}
// 判斷類是否加載到內(nèi)存中
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);
// 將處理后的cls插入到表中,即寫(xiě)到內(nèi)存中
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;
}
補(bǔ)充:之前篇章中
objc_class中有一個(gè)bits->class_data_bits_t,它下面有一個(gè)結(jié)構(gòu):
class_ro_t(ro): read only 它是從存儲(chǔ)中讀取數(shù)據(jù)到內(nèi)存中,用來(lái)存儲(chǔ)name、方法、協(xié)議和實(shí)例變量等;加載完成后,改數(shù)據(jù)不會(huì)發(fā)生變化又稱為干凈內(nèi)存(clean memory)
class_rw_t(rw): read write 存儲(chǔ)和獲取。在進(jìn)程運(yùn)行時(shí)發(fā)生更改的內(nèi)存。在數(shù)據(jù)增刪改查過(guò)程中為了不對(duì)原來(lái)數(shù)據(jù)進(jìn)行更改,為類在runtime過(guò)程中分配一個(gè)額外的內(nèi)存,從ro中copy一份data到rw中,所以它是可變的。這個(gè)內(nèi)存變成了臟內(nèi)存(dirty memory)。但是在實(shí)際應(yīng)用中,類的使用量只是10%,這樣就在rw中造成了內(nèi)存浪費(fèi),所以蘋(píng)果就把rw中方法、協(xié)議和實(shí)例變量等放到了class_rw_ext_t中。
class_rw_ext_t(rwe): read write ext,在runtime過(guò)程中存儲(chǔ)類的方法、協(xié)議和實(shí)例變量等信息。
mangledName獲取cls的name
const char *mangledName() {
// fixme can't assert locks here
// ASSERT(this);
if (!this) {
return "";
}
if (isRealized() || isFuture()) {
// 判斷如果已經(jīng)初始化or將處理的,則就從ro中讀取name
return data()->ro()->name;
} else {
// 從MachO的data中讀取name
return ((const class_ro_t *)data())->name;
}
}
addNamedClass將name、cls地址存儲(chǔ)下來(lái)
/***********************************************************************
* addNamedClass
* Adds name => cls to the named non-meta class map. 將name=> cls添加到命名的非元類映射
* Warns about duplicate class names and keeps the old mapping.關(guān)于重復(fù)的類保持舊的映射
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static void addNamedClass(Class cls, const char *name, Class replacing = nil)
{
runtimeLock.assertLocked();
Class old;
// 若dyld的共享緩存類中class有數(shù)據(jù)
if ((old = getClassExceptSomeSwift(name)) && old != replacing) {
inform_duplicate(name, old, cls);
// getMaybeUnrealizedNonMetaClass uses name lookups.
// Classes not found by name lookup must be in the
// secondary meta->nonmeta table.
// 使用name查找,未按名稱查找的類存在非元類表中
addNonMetaClass(cls);
} else {
//如果old類信息為nil,則將cls、name添加到gdb_objc_realized_classes哈希表存儲(chǔ)。gdb_objc_realized_classes:不在dyld共享緩存中的命名類
NXMapInsert(gdb_objc_realized_classes, name, cls);
}
ASSERT(!(cls->data()->flags & RO_META));
// wrong: constructed classes are already realized when they get here
// ASSERT(!cls->isRealized());
}
addClassTableEntry 將初始化之后的類存儲(chǔ)到所有類的表中,如果有元類,會(huì)自動(dòng)添加類的元類。
/***********************************************************************
* addClassTableEntry
* Add a class to the table of all classes. If addMeta is true,
* automatically adds the metaclass of the class as well.
* Locking: runtimeLock must be held by the caller.
**********************************************************************/
static void
addClassTableEntry(Class cls, bool addMeta = true)
{
runtimeLock.assertLocked();
// This class is allowed to be a known class via the shared cache or via
// data segments, but it is not allowed to be in the dynamic table already.
auto &set = objc::allocatedClasses.get();
ASSERT(set.find(cls) == set.end());
if (!isKnownClass(cls))
set.insert(cls);
if (addMeta)
addClassTableEntry(cls->ISA(), false);
}
整個(gè)以上的過(guò)程為:從_read_images,到類的處理readClass,readClass中,執(zhí)行addNamedClass,addClassTableEntry,就將cls的地址、name就存儲(chǔ)到了內(nèi)存中。
類的加載處理
在類文件中比如LGPerson中實(shí)現(xiàn)
+load
{
// ...
}
在類處理是就可以直接進(jìn)入以下代碼:實(shí)現(xiàn)非懶加載類,
// Realize non-lazy classes (for +load methods and static instances)
for (EACH_HEADER) {
//通過(guò)_getObjc2NonlazyClassList獲取Mach-O的靜態(tài)段__objc_nlclslist非懶加載類表
classref_t const *classlist =
_getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
const char *mangledName = cls->mangledName();
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
auto kc_ro = (const class_ro_t *)cls->data();
printf("_getObjc2NonlazyClassList: 這個(gè)是我要研究的 %s \n",LGPersonName);
}
//判斷是否為空。不為空則就插入表。如果前面已經(jīng)插入過(guò)了,則不會(huì)重新插入
if (!cls) continue;
addClassTableEntry(cls);
// 判斷是否為非懶加載類
if (cls->isSwiftStable()) {
// 判斷懶加載元類初始化
if (cls->swiftMetadataInitializer()) {
_objc_fatal("Swift class %s with a metadata initializer "
"is not allowed to be non-lazy",
cls->nameForLogging());
}
// fixme also disallow relocatable classes
// We can't disallow all Swift classes because of
// classes like Swift.__EmptyArrayStorage
}
//實(shí)現(xiàn)加載所有非懶加載的類(實(shí)例化類對(duì)象的一些信息,例如rw)
realizeClassWithoutSwift(cls, nil);
}
}
- 1.讀取一個(gè)非懶加載
classlist,對(duì)其進(jìn)行遍歷,如果該遍歷的cls已經(jīng)存在表中,則繼續(xù)。如果沒(méi)有則添加到類表中。 - 2.
realizeClassWithoutSwift實(shí)現(xiàn)遍歷的當(dāng)前類,加載出除cls地址、name之外的data數(shù)據(jù)。
realizeClassWithoutSwift->實(shí)現(xiàn)類
對(duì)類cls進(jìn)行首次初始化,包括分配其讀寫(xiě)數(shù)據(jù),返回類的真實(shí)類結(jié)構(gòu)。代碼量挺多的就研究分析流程了。
該方法在分析消息流程的慢速查找流程時(shí)也出現(xiàn)過(guò),判斷類是否初始化,如果未初始化,則初始化cls,并最后實(shí)現(xiàn)類。
lookUpImpOrForward -> realizeClassMaybeSwiftAndLeaveLocked -> realizeClassMaybeSwiftMaybeRelock -> realizeClassWithoutSwift
OC底層原理08-objc_msgSend方法消息慢速查找(二)
- 1.讀取MachO的data
將cls的data數(shù)據(jù)讀取出來(lái),并轉(zhuǎn)換為class_ro_t *,賦值給一個(gè)ro.并且復(fù)制一份data給rw。
auto ro = (const class_ro_t *)cls->data();
auto isMeta = ro->flags & RO_META;
// 判斷是否為未來(lái)才處理的類
if (ro->flags & RO_FUTURE) {
// This was a future class. rw data is already allocated. 分配rw
rw = cls->data();
ro = cls->data()->ro();
ASSERT(!isMeta);
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data.正常類的情況就寫(xiě)入分配類data
// 開(kāi)票一個(gè)空間給rw。
rw = objc::zalloc<class_rw_t>();
// 設(shè)置rw中ro
rw->set_ro(ro); //
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
cls->setData(rw); // 把rw的數(shù)據(jù)寫(xiě)入 :setData(rw) -> bits.setData(newData);
}
查看set_ro的實(shí)現(xiàn),可以發(fā)現(xiàn)set_ro -> set_ro_or_rwe(找到 get_ro_or_rwe,是通過(guò)ro_or_rw_ext_t類型從ro_or_rw_ext中獲?。?-> ro_or_rw_ext_t中的ro.如果有運(yùn)行時(shí),從rw中讀取;反之,如果沒(méi)有運(yùn)行時(shí),從ro中讀取.
- 2.確定集成鏈
遞歸調(diào)用realizeClassWithoutSwift,目的是為了本類的父類、元類的繼承鏈,并實(shí)現(xiàn)了它們。
// Realize superclass and metaclass, if they aren't already.
// This needs to be done after RW_REALIZED is set above, for root classes.
// This needs to be done after class index is chosen, for root metaclasses.
// This assumes that none of those classes have Swift contents,
// or that Swift's initializers have already been called.
// fixme that assumption will be wrong if we add support
// for ObjC subclasses of Swift classes.
supercls = realizeClassWithoutSwift(remapClass(cls->superclass), nil);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
// Connect this class to its superclass's subclass lists
//雙向鏈表指向關(guān)系 父類中可以找到子類 子類中也可以找到父類
//通過(guò)addSubclass把當(dāng)前類放到父類的子類列表中去
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
-
setInstancesRequireRawIsaormethodizeClass
-
#if SUPPORT_NONPOINTER_ISA
if (isMeta) {
// Metaclasses do not need any features from non pointer ISA
// This allows for a faspath for classes in objc_retain/objc_release.
cls->setInstancesRequireRawIsa();
} else {
// Disable non-pointer isa for some classes and/or platforms.
// Set instancesRequireRawIsa.
bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
bool rawIsaIsInherited = false;
static bool hackedDispatch = false;
if (DisableNonpointerIsa) {
// Non-pointer isa disabled by environment or app SDK version
instancesRequireRawIsa = true;
}
else if (!hackedDispatch && 0 == strcmp(ro->name, "OS_object"))
{
// hack for libdispatch et al - isa also acts as vtable pointer
hackedDispatch = true;
instancesRequireRawIsa = true;
}
else if (supercls && supercls->superclass &&
supercls->instancesRequireRawIsa())
{
// This is also propagated by addSubclass()
// but nonpointer isa setup needs it earlier.
// Special case: instancesRequireRawIsa does not propagate
// from root class to root metaclass
instancesRequireRawIsa = true;
rawIsaIsInherited = true;
}
if (instancesRequireRawIsa) {
cls->setInstancesRequireRawIsaRecursively(rawIsaIsInherited);
}
}
// SUPPORT_NONPOINTER_ISA
#endif
// Update superclass and metaclass in case of remapping
cls->superclass = supercls;
cls->initClassIsa(metacls);
// Reconcile instance variable offsets / layout.
// This may reallocate class_ro_t, updating our ro variable.
if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);
// Set fastInstanceSize if it wasn't set already.
cls->setInstanceSize(ro->instanceSize);
// Copy some flags from ro to rw
if (ro->flags & RO_HAS_CXX_STRUCTORS) {
cls->setHasCxxDtor();
if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
cls->setHasCxxCtor();
}
}
// Propagate the associated objects forbidden flag from ro or from
// the superclass.
if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
(supercls && supercls->forbidsAssociatedObjects()))
{
rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
}
// Connect this class to its superclass's subclass lists
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
// Attach categories 附加類別 將ro數(shù)據(jù)中方法列表(包括分類的方法)、屬性列表、協(xié)議列表都寫(xiě)入到rw
methodizeClass(cls, previously);
return cls;
在main.m文件中調(diào)用一個(gè)類的初始化方法,在此處斷點(diǎn)調(diào)試;首次進(jìn)入該段代碼,會(huì)先走cls->instancesRequireRawIsa();流程,深入一下,就能找到
inline void
objc_object::initClassIsa(Class cls)
{
if (DisableNonpointerIsa || cls->instancesRequireRawIsa()) {
initIsa(cls, false/*not nonpointer*/, false);
} else {
initIsa(cls, true/*nonpointer*/, false);
}
}
就是一個(gè)初始化isa的必要條件。
我們?cè)谶@里打印一下cls,能獲取到cls的信息。
(lldb) x/4gx cls
0x1000032e8: 0x00000001000032c0 0x0000000100335140
0x1000032f8: 0x000000010032f430 0x0000000000000000
// 依次是: isa ,繼承,cache,bits
此時(shí)還未初始化,所以最后一個(gè)地址沒(méi)有數(shù)據(jù),是因?yàn)閮?nèi)存情況還未完善。但是如果這樣(const class_ro_t *)cls->data();是能獲取到data數(shù)據(jù)的,通過(guò)指針是可以獲取到數(shù)據(jù)的。
初始化空間,設(shè)置cls數(shù)據(jù)
// Set fastInstanceSize if it wasn't set already.
cls->setInstanceSize(ro->instanceSize);
// Copy some flags from ro to rw
if (ro->flags & RO_HAS_CXX_STRUCTORS) {
cls->setHasCxxDtor();
if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
cls->setHasCxxCtor();
}
}
cls就有了初始值
(lldb) x/4gx cls
0x1000032e8: 0x00000001000032c0 0x0000000100335140
0x1000032f8: 0x000000010032f430 0x0000202400000000
根據(jù)數(shù)據(jù)流 : cls->data() -> ro -> rw ,rw數(shù)據(jù)里面的rwe是在methodizeClass中處理的。
methodizeClass
/***********************************************************************
* methodizeClass
* Fixes up cls's method list, protocol list, and property list.
* Attaches any outstanding categories.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static void methodizeClass(Class cls, Class previously)
{
runtimeLock.assertLocked();
bool isMeta = cls->isMetaClass();
auto rw = cls->data();
auto ro = rw->ro();
auto rwe = rw->ext(); // rw中的ext 數(shù)據(jù)賦值給rwe
// Methodizing for the first time
if (PrintConnecting) {
_objc_inform("CLASS: methodizing class '%s' %s",
cls->nameForLogging(), isMeta ? "(meta)" : "");
}
// Install methods and properties that the class implements itself.
method_list_t *list = ro->baseMethods(); // 獲取方法列表
if (list) {
// 對(duì)方法列表進(jìn)行排序
prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
if (rwe) rwe->methods.attachLists(&list, 1);
}
property_list_t *proplist = ro->baseProperties;
if (rwe && proplist) {
rwe->properties.attachLists(&proplist, 1);
}
protocol_list_t *protolist = ro->baseProtocols;
if (rwe && protolist) {
rwe->protocols.attachLists(&protolist, 1);
}
// Root classes get bonus method implementations if they don't have them already. These apply before category replacements.
if (cls->isRootMetaclass()) {
// root metaclass
addMethod(cls, @selector(initialize), (IMP)&objc_noop_imp, "", NO);
}
// Attach categories.
if (previously) {
if (isMeta) {
objc::unattachedCategories.attachToClass(cls, previously,
ATTACH_METACLASS);
} else {
// When a class relocates, categories with class methods
// may be registered on the class itself rather than on
// the metaclass. Tell attachToClass to look for those.
objc::unattachedCategories.attachToClass(cls, previously,
ATTACH_CLASS_AND_METACLASS);
}
}
objc::unattachedCategories.attachToClass(cls, cls,
isMeta ? ATTACH_METACLASS : ATTACH_CLASS);
#if DEBUG
// Debug: sanity-check all SELs; log method list contents
for (const auto& meth : rw->methods()) {
if (PrintConnecting) {
_objc_inform("METHOD %c[%s %s]", isMeta ? '+' : '-',
cls->nameForLogging(), sel_getName(meth.name));
}
ASSERT(sel_registerName(sel_getName(meth.name)) == meth.name);
}
#endif
}
- 在該方法中,進(jìn)行了
ro、rw、rwe初始賦值后。從ro總讀取到方法列表,將方法列表轉(zhuǎn)換為method_list_t類型的list; - 對(duì)方法列表進(jìn)行排序
prepareMethodLists(屬性、方法、協(xié)議表)。
static void
prepareMethodLists(Class cls, method_list_t **addedLists, int addedCount,
bool baseMethods, bool methodsFromBundle)
{
// ...
// Add method lists to array.
// Reallocate un-fixed method lists.
// The new methods are PREPENDED to the method list array.
for (int i = 0; i < addedCount; i++) {
method_list_t *mlist = addedLists[i];
ASSERT(mlist);
// Fixup selectors if necessary
if (!mlist->isFixedUp()) {
fixupMethodList(mlist, methodsFromBundle, true/*sort*/);//排序
}
}
// ...
}
// ----------------------
static void
fixupMethodList(method_list_t *mlist, bool bundleCopy, bool sort)
{
runtimeLock.assertLocked();
ASSERT(!mlist->isFixedUp());
// fixme lock less in attachMethodLists ?
// dyld3 may have already uniqued, but not sorted, the list
if (!mlist->isUniqued()) {
mutex_locker_t lock(selLock);
// Unique selectors in list.
for (auto& meth : *mlist) {
const char *name = sel_cname(meth.name);
meth.name = sel_registerNameNoLock(name, bundleCopy);
}
}
// Sort by selector address.根據(jù)sel地址排序
if (sort) {
method_t::SortBySELAddress sorter;
std::stable_sort(mlist->begin(), mlist->end(), sorter);
}
// Mark method list as uniqued and sorted
mlist->setFixedUp();
}
方法的排序原則是:根據(jù)sel地址排序
- 序列化各list之后,對(duì)rwe進(jìn)行了賦值,此時(shí)rwe就有了值:
rwe->methods.attachLists。
void attachToClass(Class cls, Class previously, int flags)
{
runtimeLock.assertLocked();
ASSERT((flags & ATTACH_CLASS) ||
(flags & ATTACH_METACLASS) ||
(flags & ATTACH_CLASS_AND_METACLASS));
const char *mangledName = cls->mangledName();
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
bool kc_isMeta = cls->isMetaClass();
auto kc_rw = cls->data();
auto kc_ro = kc_rw->ro();
if (!kc_isMeta) {
printf("%s: 這個(gè)是我要研究的 %s \n",__func__,LGPersonName);
}
}
auto &map = get();
auto it = map.find(previously);//找到一個(gè)分類進(jìn)來(lái)一次,即一個(gè)個(gè)加載分類,不要混亂
if (it != map.end()) {//這里會(huì)走進(jìn)來(lái):當(dāng)主類沒(méi)有實(shí)現(xiàn)load,分類開(kāi)始加載,迫使主類加載,會(huì)走到if流程里面
category_list &list = it->second;
if (flags & ATTACH_CLASS_AND_METACLASS) {//判斷是否是元類
int otherFlags = flags & ~ATTACH_CLASS_AND_METACLASS;
attachCategories(cls, list.array(), list.count(), otherFlags | ATTACH_CLASS);//實(shí)例方法
attachCategories(cls->ISA(), list.array(), list.count(), otherFlags | ATTACH_METACLASS);//類方法
} else {
//如果不是元類,則只走一次 attachCategories
attachCategories(cls, list.array(), list.count(), flags);
}
map.erase(it);
}
}
在 category_list -> attachCategories中有了對(duì)分類的操作處理,那么就需要對(duì)分類是如何加載再做一個(gè)探究—類加載(二)。
懶加載類&非懶加載類
區(qū)別:當(dāng)前類是否實(shí)現(xiàn)load方法;不實(shí)現(xiàn)它就是懶加載,實(shí)現(xiàn)了+load則是非懶加載。
1.懶加載類情況
把數(shù)據(jù)加載推遲到第一次消息
lookUpImpOrForward
realizeClassMaybeSwiftMaybeRelock
realizeClassWithoutSwift
methodizeClass2.非懶加載類情況
實(shí)現(xiàn)load方法,在map_images的時(shí)候,就加載所有類數(shù)據(jù)
_getObjc2NonlazyClassList
readClass
realizeClassWithoutSwift
methodizeClass
蘋(píng)果方默認(rèn)為了性能是采取懶加載類。