前言
前篇 我們了解到 應(yīng)用的加載流程,在
main函數(shù)調(diào)用之前有許多系統(tǒng)的操作流程,但是在分析類的加載需要明確的是main函數(shù)才是我們app程序的入口函數(shù),我們知道 在執(zhí)行main函數(shù)之前,系統(tǒng)會(huì)對(duì)runtime進(jìn)行初始化,在之前我們了解到dyld會(huì)調(diào)用runtime的入口函數(shù),runtime的入口函數(shù) 就是_objc_iinnit,它就是在mian函數(shù)之前就被dyld調(diào)用,而load方法就在_objc_init中調(diào)用,所以 我們探究的起點(diǎn)就是_objc_init函數(shù)
image.png
一 _objc_init 探究分析
我們?cè)趓untime的源碼中 可以了解到_objc_init 的源代碼
/***********************************************************************
* _objc_init
* Bootstrap initialization. Registers our image notifier with dyld.
* Called by libSystem BEFORE library initialization time
**********************************************************************/
void _objc_init(void)
{
static bool initialized = false;
if (initialized) return;
initialized = true;
// fixme defer initialization until an objc-using image is found?
environ_init(); // 環(huán)境變量
tls_init(); //線程 key 的綁定
static_init(); //初始化系統(tǒng)內(nèi)置的 C++ 靜態(tài)構(gòu)造函數(shù)
runtime_init(); //主要是運(yùn)行時(shí)的初始化,主要分為兩部分:分類初始化(unattachedCategories)和類的表初始化(allocatedClasses)
exception_init(); // 初始化libobjc異常處理
cache_init(); //緩存初始化
_imp_implementationWithBlock_init(); //啟動(dòng)機(jī)制回調(diào)
// 注冊(cè)回調(diào)通知
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
#if __OBJC2__
didCallDyldNotifyRegister = true;
#endif
}·
二 _dyld_objc_notify_register 解析
//
// Note: only for use by objc runtime
// Register handlers to be called when objc images are mapped, unmapped, and initialized.
// Dyld will call back the "mapped" function with an array of images that contain an objc-image-info section.
// Those images that are dylibs will have the ref-counts automatically bumped, so objc will no longer need to
// call dlopen() on them to keep them from being unloaded. During the call to _dyld_objc_notify_register(),
// dyld will call the "mapped" function with already loaded objc images. During any later dlopen() call,
// dyld will also call the "mapped" function. Dyld will call the "init" function when dyld would be called
// initializers in that image. This is when objc calls any +load methods in that image.
//
// 翻譯如下:
// 注意: 只能在objc runtime 中使用
// 注冊(cè)回調(diào)函數(shù), 當(dāng) objc 庫 映射,未映射,和初始化的時(shí)候調(diào)用
// dyld將要調(diào)用包含objc-image-info的鏡像數(shù)組回調(diào)的“mapped”函數(shù)。
// dyld 會(huì)為這些鏡像自動(dòng)增加引用技術(shù),所以objc 不需要使用dlopen函數(shù)保證它不被卸載。
// 在調(diào)用 `_dyld_objc_notify_register` 的過程中,dyld 會(huì)調(diào)用已經(jīng)加載的鏡像的 mapped 函數(shù)
// 在之后的任何dlopen()調(diào)用期間,dyld也將調(diào)用“映射”函數(shù)。
// 在dyld 調(diào)用鏡像的initializers 的時(shí)候,dyld 將調(diào)用 init
// 這是objc在這個(gè)鏡像中調(diào)用所有+ load方法的時(shí)候。
void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
_dyld_objc_notify_init init,
_dyld_objc_notify_unmapped unmapped);
_dyld_objc_notify_register 實(shí)現(xiàn)
void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
_dyld_objc_notify_init init,
_dyld_objc_notify_unmapped unmapped)
{
dyld::registerObjCNotifiers(mapped, init, unmapped);
}
注冊(cè)回調(diào)通知
參數(shù)介紹
- _dyld_objc_notify_mapped : dyld 將 image 加載進(jìn)內(nèi)存時(shí) , 會(huì)觸發(fā)該函數(shù).
- _dyld_objc_notify_init : dyld 初始化 image 會(huì)觸發(fā)該方法. ( 我們所熟知的 load 方法也是在此處調(diào)用 ) .
- unmap__dyld_objc_notify_unmapped: dyld 將 image 移除時(shí) , 會(huì)觸發(fā)該函數(shù) .
這三個(gè)回調(diào)函數(shù) 在runtime 中分別對(duì)應(yīng)著 map_images, load_images, unmap_image
三 map_images 將image 加載進(jìn)內(nèi)存回調(diào)
- map_images
/***********************************************************************
* map_images
* Process the given images which are being mapped in by dyld.
* Calls ABI-agnostic code after taking ABI-specific locks.
*
* Locking: write-locks runtimeLock
**********************************************************************/
void
map_images(unsigned count, const
char * const paths[],
const struct mach_header * const mhdrs[])
{
mutex_locker_t lock(runtimeLock);
return map_images_nolock(count, paths, mhdrs);
}
map_images 方法在 image 加載到內(nèi)存的時(shí)候會(huì)觸發(fā)該方法的調(diào)用
- map_images_nolock
void
map_images_nolock(unsigned mhCount, const char * const mhPaths[],
const struct mach_header * const mhdrs[])
{
... 代碼省略
if (hCount > 0) {
// 讀取鏡像文件
_read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
}
firstTime = NO;
// Call image load funcs after everything is set up.
for (auto func : loadImageFuncs) {
for (uint32_t i = 0; i < mhCount; i++) {
func(mhdrs[i]);
}
}
}
四 _read_images 讀取鏡像
主要內(nèi)容是:條件控制只執(zhí)行一次、處理編譯階段SEL混亂的問題、錯(cuò)誤的類處理、加載協(xié)議、分類處理、類的讀取、以及針對(duì)某些非懶加載的在直接進(jìn)行實(shí)現(xiàn)。
我們現(xiàn)在分段進(jìn)行解析,通過 ts.log進(jìn)行分段分析
4.1 創(chuàng)建表
... 省略
if (!doneOnce) {
doneOnce = YES;
...省略
// namedClasses
// Preoptimized classes don't go in this table.
// 4/3 is NXMapTable's load factor
int namedClassesSize =
(isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
// 實(shí)例化存儲(chǔ)類的哈希表
gdb_objc_realized_classes =
NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
ts.log("IMAGE TIMES: first time tasks");
}
- gdb_objc_realized_classes存儲(chǔ)不在共享緩存且已命名的所有類,其容量是類數(shù)量的4/3
// This is a misnomer: gdb_objc_realized_classes is actually a list of
// named classes not in the dyld shared cache, whether realized or not.
NXMapTable *gdb_objc_realized_classes; // exported for debuggers in objc-gdb.h
4.2 sel_registerNameNoLock 處理編譯階段SEL混亂的問題
// 修復(fù)預(yù)編譯階段的@selector的混亂問題
static size_t UnfixedSelectors;
{
mutex_locker_t lock(selLock);
for (EACH_HEADER) {
if (hi->hasPreoptimizedSelectors()) continue;
bool isBundle = hi->isBundle();
// 從macho 文件中 獲取方法名稱
SEL *sels = _getObjc2SelectorRefs(hi, &count);
UnfixedSelectors += count;
for (i = 0; i < count; i++) {
// sel_cname 將 SEL 強(qiáng)轉(zhuǎn)為 char 類型
const char *name = sel_cname(sels[i]);
// 注冊(cè) SEL 的操作
SEL sel = sel_registerNameNoLock(name, isBundle);
if (sels[i] != sel) {
sels[i] = sel;
}
}
}
}
ts.log("IMAGE TIMES: fix up selector references");
-
_getObjc2SelectorRefs:其中_getObjc2SelectorRefs的源碼如下,表示獲取Mach-O中的靜態(tài)段__objc_selrefs
// 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");
-
sel_cname:其中SEL --> sel并不是簡(jiǎn)單的字符串,是帶地址的字符串 如下所示,sels[i]與sel字符串一致,但是地址不一致,所以需要調(diào)整為一致的。即fix up
image.png
4.3 readClass 重點(diǎn)
// Discover classes. Fix up unresolved future classes. Mark bundle classes.
bool hasDyldRoots = dyld_shared_cache_some_image_overridden();
// 從編譯后的類列表中取出所有類,獲取到的是一個(gè)classref_t類型的指針
for (EACH_HEADER) {
if (! mustReadClasses(hi, hasDyldRoots)) {
// Image is sufficiently optimized that we need not call readClass()
// 鏡像充分優(yōu)化,我們不需要調(diào)用 readClass()
continue;
}
classref_t const *classlist = _getObjc2ClassList(hi, &count);
bool headerIsBundle = hi->isBundle();
bool headerIsPreoptimized = hi->hasPreoptimizedClasses();
for (i = 0; i < count; i++) {
//數(shù)組中會(huì)取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunloop等系統(tǒng)類,例如CF、Fundation、libdispatch中的類。以及自己創(chuàng)建的類
Class cls = (Class)classlist[i];
// 通過 readClass 函數(shù)獲取處理后的新類,內(nèi)部主要操作 ro 和 rw 結(jié)構(gòu)體
Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
// 初始化所有懶加載的類需要的內(nèi)存空間,并將所有的未來需要處理的類添加到一個(gè)數(shù)組中
// 現(xiàn)在數(shù)據(jù)沒有加載到的,連類都沒有初始化
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");
- read_class
/***********************************************************************
* readClass
* Read a class and metaclass as written by a compiler.
* Returns the new class pointer. This could be:
* - cls
* - nil (cls has a missing weak-linked superclass)
* - something else (space for this class was reserved by a future class)
*
* Note that all work performed by this function is preflighted by
* mustReadClasses(). Do not change this function without updating that one.
*
* Locking: runtimeLock acquired by map_images or objc_readClassPair
**********************************************************************/
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
// 已經(jīng)實(shí)現(xiàn)類從內(nèi)存中讀取,未實(shí)現(xiàn)的類從 mach-o 中讀取
const char *mangledName = cls->mangledName();
// 測(cè)試代碼
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
printf("%s ---- %s",__func__ , mangledName);
}
// 如果某個(gè) cls 的 superclass 是 weak-linked 的并且丟失了,則返回YES。
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());
}
// 添加到重映射表里面,映射為 nil
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 {
// 重點(diǎn):從mach-o 文件讀取插入到這兩個(gè)表里面,自此在內(nèi)存中就可以讀到這個(gè)類了
// 將 cls 加入到 gdb_objc_realized_classes 表里面去
addNamedClass(cls, mangledName, replacing);
// 將 cls 插入到 allocatedClasses 表里面去
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;
}
// 返回這個(gè)類
return cls;
}
- addNamedClass
將當(dāng)前類添加到已創(chuàng)建好的gdb_objc_realized_classes哈希表(存放所有類)
/***********************************************************************
* addNamedClass
* Adds name => cls to the named non-meta class map.
* Warns about duplicate class names and keeps the old mapping.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static void addNamedClass(Class cls, const char *name, Class replacing = nil)
{
runtimeLock.assertLocked();
Class old;
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.
addNonMetaClass(cls);
} else {
// 將類名插入類表中
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
當(dāng)前類已經(jīng)初始化,所以要添加到allocatedClasses哈希表,并添加元類
/***********************************************************************
* 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());
// 未識(shí)別的類
if (!isKnownClass(cls))
set.insert(cls);
if (addMeta)
addClassTableEntry(cls->ISA(), false);
// 開辟空間-元類遞歸-元類開辟空間-元類名稱插入類表
}
- 注意:
第三步 類處理(readClass)中 內(nèi)部并沒有完成類的加載,只是將類名 和 類地址 記錄到了類表中
4.4 修復(fù)重映射
// 將未映射Class和Super Class重映射,被remap的類都是非懶加載的類
// Fix up remapped classes
// Class list and nonlazy class list remain unremapped.
// Class refs and super refs are remapped for message dispatching.
if (!noClassesRemapped()) {
for (EACH_HEADER) {
// 重映射Class,注意是從_getObjc2ClassRefs函數(shù)中取出類的引用
Class *classrefs = _getObjc2ClassRefs(hi, &count);
for (i = 0; i < count; i++) {
remapClassRef(&classrefs[i]);
}
// fixme why doesn't test future1 catch the absence of this?
classrefs = _getObjc2SuperRefs(hi, &count);
for (i = 0; i < count; i++) {
remapClassRef(&classrefs[i]);
}
}
}
ts.log("IMAGE TIMES: remap classes");
4.5 fixupMessageRef: 修復(fù)舊的函數(shù)指針調(diào)用遺留
// Fix up old objc_msgSend_fixup call sites
for (EACH_HEADER) {
message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
if (count == 0) continue;
if (PrintVtables) {
_objc_inform("VTABLES: repairing %zu unsupported vtable dispatch "
"call sites in %s", count, hi->fname());
}
for (i = 0; i < count; i++) {
// 內(nèi)部將常用的alloc、objc_msgSend等函數(shù)指針進(jìn)行注冊(cè),并fix為新的函數(shù)指針
fixupMessageRef(refs+i);
}
}
ts.log("IMAGE TIMES: fix up objc_msgSend_fixup");
4.6 readProtocol :讀取并初始化Protocol
bool cacheSupportsProtocolRoots = sharedCacheSupportsProtocolRoots();
// Discover protocols. Fix up protocol refs.
// 遍歷所有協(xié)議列表,并且將協(xié)議列表加載到Protocol的哈希表中
for (EACH_HEADER) {
extern objc_class OBJC_CLASS_$_Protocol;
// 獲取協(xié)議類 cls = Protocol類
Class cls = (Class)&OBJC_CLASS_$_Protocol;
ASSERT(cls);
// 獲取protocol哈希表
NXMapTable *protocol_map = protocols();
bool isPreoptimized = hi->hasPreoptimizedProtocols();
// Skip reading protocols if this is an image from the shared cache
// and we support roots
// Note, after launch we do need to walk the protocol as the protocol
// in the shared cache is marked with isCanonical() and that may not
// be true if some non-shared cache binary was chosen as the canonical
// definition
if (launchTime && isPreoptimized && cacheSupportsProtocolRoots) {
if (PrintProtocols) {
_objc_inform("PROTOCOLS: Skipping reading protocols in image: %s",
hi->fname());
}
continue;
}
bool isBundle = hi->isBundle();
// 從編譯器中讀取并初始化Protocol
protocol_t * const *protolist = _getObjc2ProtocolList(hi, &count);
for (i = 0; i < count; i++) {
readProtocol(protolist[i], cls, protocol_map,
isPreoptimized, isBundle);
}
ts.log("IMAGE TIMES: discover protocols");
4.7 修復(fù)協(xié)議列表引用
// Fix up @protocol references
// Preoptimized images may have the right
// answer already but we don't know for sure.
// 修復(fù)協(xié)議列表引用,優(yōu)化后的images可能是正確的,但是并不確定
for (EACH_HEADER) {
// At launch time, we know preoptimized image refs are pointing at the
// shared cache definition of a protocol. We can skip the check on
// launch, but have to visit @protocol refs for shared cache images
// loaded later.
if (launchTime && cacheSupportsProtocolRoots && hi->isPreoptimized())
continue;
// 需要注意到是,下面的函數(shù)是_getObjc2ProtocolRefs,和上面的_getObjc2ProtocolList不一樣
protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);
for (i = 0; i < count; i++) {
remapProtocolRef(&protolist[i]);
}
}
ts.log("IMAGE TIMES: fix up @protocol references");
4.8 分類的加載
// Discover categories. Only do this after the initial category
// attachment has been done. For categories present at startup,
// discovery is deferred until the first load_images call after
// the call to _dyld_objc_notify_register completes. rdar://problem/53119145
// 發(fā)現(xiàn)分類。僅在完成初始類別附件后才執(zhí)行此操作。 對(duì)于啟動(dòng)時(shí)出現(xiàn)的類別,發(fā)現(xiàn)將推遲到對(duì)_dyld_objc_notify_register的調(diào)用完成后的第一個(gè)load_images調(diào)用為止。
if (didInitialAttachCategories) {
for (EACH_HEADER) {
load_categories_nolock(hi);
}
}
ts.log("IMAGE TIMES: discover categories");
4.9 非懶加載的類
非懶加載類定義:實(shí)現(xiàn)了+load方法 和 靜態(tài)初始化的類是非懶加載類,否則就是懶加載類
// Category discovery MUST BE Late to avoid potential races
// when other threads call the new category code before
// this thread finishes its fixups.
// +load handled by prepare_load_methods()
// Realize non-lazy classes (for +load methods and static instances)
for (EACH_HEADER) {
classref_t const *classlist =
_getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
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);
}
}
ts.log("IMAGE TIMES: realize non-lazy classes");
_getObjc2NonlazyClassList獲取到__objc_nlclslist,取出非懶加載類addClassTableEntry再加載一遍——如果已添加就不會(huì)添加進(jìn)去,確保整個(gè)結(jié)構(gòu)都被添加realizeClassWithoutSwift是接下來要關(guān)注的地方realizeClassWithoutSwift 分析
static Class realizeClassWithoutSwift(Class cls, Class previously)
{
runtimeLock.assertLocked();
class_rw_t *rw;
Class supercls;
Class metacls;
if (!cls) return nil;
if (cls->isRealized()) return cls;
// 判斷 cls 是否已經(jīng)初始化,里面是對(duì) data()->flags 的判斷
ASSERT(cls == remapClass(cls));
// fixme verify class is not in an un-dlopened part of the shared cache?
// 驗(yàn)證類不在共享緩存的未刪除部分
auto ro = (const class_ro_t *)cls->data();
// 判斷類是否是未實(shí)現(xiàn)的未來類
auto isMeta = ro->flags & RO_META;
if (ro->flags & RO_FUTURE) {
// 是未來的類. rw 已經(jīng)被初始化
rw = cls->data();
ro = cls->data()->ro();
ASSERT(!isMeta);
// 修改 flags
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data.
// 正常的類. 分配可寫的類數(shù)據(jù)。
// 開辟 rw 內(nèi)存空間
rw = objc::zalloc<class_rw_t>();
rw->set_ro(ro);
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
cls->setData(rw);
// 注: rw ro rwe
//
}
// 判斷是否是元類
#if FAST_CACHE_META
if (isMeta) cls->cache.setBit(FAST_CACHE_META);
#endif
// Choose an index for this class.
// Sets cls->instancesRequireRawIsa if indexes no more indexes are available
// 設(shè)置cls->instancesRequireRawIsa如果沒有更多的索引可用
cls->chooseClassArrayIndex();
if (PrintConnecting) {
_objc_inform("CLASS: realizing class '%s'%s %p %p #%u %s%s",
cls->nameForLogging(), isMeta ? " (meta)" : "",
(void*)cls, ro, cls->classArrayIndex(),
cls->isSwiftStable() ? "(swift)" : "",
cls->isSwiftLegacy() ? "(pre-stable swift)" : "");
}
// 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.
// 遞歸調(diào)用,實(shí)現(xiàn)父類和元類
supercls = realizeClassWithoutSwift(remapClass(cls->superclass), nil);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
#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.
// 禁用一些類和非指針isa
bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
bool rawIsaIsInherited = false;
static bool hackedDispatch = false;
// 禁用非指針的 isa
if (DisableNonpointerIsa) {
// Non-pointer isa disabled by environment or app SDK version
// 非指針isa禁用的環(huán)境或應(yīng)用程序SDK版本
instancesRequireRawIsa = true;
}
else if (!hackedDispatch && 0 == strcmp(ro->name, "OS_object"))
{
// 在 hackedDispatch 里 isa 也充當(dāng)虛表指針
hackedDispatch = true;
instancesRequireRawIsa = true;
}
else if (supercls && supercls->superclass &&
supercls->instancesRequireRawIsa())
{
// 從元類到根元類設(shè)置
instancesRequireRawIsa = true;
rawIsaIsInherited = true;
}
if (instancesRequireRawIsa) {
cls->setInstancesRequireRawIsaRecursively(rawIsaIsInherited);
}
}
// SUPPORT_NONPOINTER_ISA
#endif
// 在重新映射時(shí)更新父類和元類
// Update superclass and metaclass in case of remapping
cls->superclass = supercls;
cls->initClassIsa(metacls);
// 協(xié)調(diào)實(shí)例變量的偏移量/布局,可能會(huì)重新分配 class_ro_t,更新我們的 ro 變量。
if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);
// 如果還沒有設(shè)置就開始設(shè)置 fastInstanceSize。
cls->setInstanceSize(ro->instanceSize);
// 將一些標(biāo)志從 ro 復(fù)制到 rw
if (ro->flags & RO_HAS_CXX_STRUCTORS) {
cls->setHasCxxDtor();
if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
cls->setHasCxxCtor();
}
}
// 從ro或父類中傳播關(guān)聯(lián)的對(duì)象禁止標(biāo)志
if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
(supercls && supercls->forbidsAssociatedObjects()))
{
rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
}
// 將這個(gè)類連接到它的父類的子類列表,即雙向綁定
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
// 整理 cls 的方法列表、協(xié)議列表和屬性列表,以及附加任何未完成的類別
methodizeClass(cls, previously);
return cls;
}
- 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();
// 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.
// 將 ro 里面的方法附加到 rw 里面去
method_list_t *list = ro->baseMethods();
if (list) {
prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
if (rwe) rwe->methods.attachLists(&list, 1);
}
// 將 ro 里面的屬性附加到 rw 里面去
property_list_t *proplist = ro->baseProperties;
if (rwe && proplist) {
rwe->properties.attachLists(&proplist, 1);
}
// 將 ro 里面的協(xié)議附加到 rw 里面去
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.
// 根類獲得額外的方法實(shí)現(xiàn),如果它們還沒有。這些適用于類別替換之前。
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
}
- attachLists 分析
// 基本上方法、協(xié)議、屬性都是通過 attachLists 函數(shù)附加到對(duì)應(yīng)的列表上的
void attachLists(List* const * addedLists, uint32_t addedCount) {
if (addedCount == 0) return;
if (hasArray()) {
// many lists -> many lists
//計(jì)算數(shù)組中舊lists的大小
uint32_t oldCount = array()->count;
//計(jì)算新的容量大小 = 舊數(shù)據(jù)大小+新數(shù)據(jù)大小
uint32_t newCount = oldCount + addedCount;
//根據(jù)新的容量大小,開辟一個(gè)數(shù)組,類型是 array_t,通過array()獲取
setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
//設(shè)置數(shù)組大小
array()->count = newCount;
//舊的數(shù)據(jù)從 addedCount 數(shù)組下標(biāo)開始 存放舊的lists,大小為 舊數(shù)據(jù)大小 * 單個(gè)舊list大小
memmove(array()->lists + addedCount, array()->lists,
oldCount * sizeof(array()->lists[0]));
//新數(shù)據(jù)從數(shù)組 首位置開始存儲(chǔ),存放新的lists,大小為 新數(shù)據(jù)大小 * 單個(gè)list大小
memcpy(
array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
else if (!list && addedCount == 1) {
// 0 lists -> 1 list
list = addedLists[0];//將list加入mlists的第一個(gè)元素,此時(shí)的list是一個(gè)一維數(shù)組
}
else {
// 1 list -> many lists 有了一個(gè)list,有往里加很多l(xiāng)ist
//新的list就是分類,來自LRU的算法思維,即最近最少使用
//獲取舊的list
List* oldList = list;
uint32_t oldCount = oldList ? 1 : 0;
//計(jì)算容量和 = 舊list個(gè)數(shù)+新lists的個(gè)數(shù)
uint32_t newCount = oldCount + addedCount;
//開辟一個(gè)容量和大小的集合,類型是 array_t,即創(chuàng)建一個(gè)數(shù)組,放到array中,通過array()獲取
setArray((array_t *)malloc(array_t::byteSize(newCount)));
//設(shè)置數(shù)組的大小
array()->count = newCount;
//判斷old是否存在,old肯定是存在的,將舊的list放入到數(shù)組的末尾
if (oldList) array()->lists[addedCount] = oldList;
// memcpy(開始位置,放什么,放多大) 是內(nèi)存平移,從數(shù)組起始位置存入新的list
//其中array()->lists 表示首位元素位置
memcpy(array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
}


