一彩掐、objc
查看objc源碼的時候看到了void _objc_init(void)
函數(shù)
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();
tls_init();
static_init();
runtime_init();
exception_init();
cache_init();
_imp_implementationWithBlock_init();
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
#if __OBJC2__
didCallDyldNotifyRegister = true;
#endif
}
那這個方法什么時候進來的呢,我們打一個斷點,通過lldb
的bt
命令看一下堆棧
結(jié)合這張圖我們得知
_objc_init
調(diào)用流程大致為:
dyld的
doModInitFunctions
方法調(diào)用libSystem.B.dylib的libSystem_initializer
方法毛仪;接著初始化了libdispatch; libdispatch又調(diào)用了_os_object_int
,最終來到了_objc_init
- 1叛买、這里其實是各種初始化:環(huán)境初始化;靜態(tài)變量初始化飞涂;運行時初始化赶舆;異常初始化踪栋;cache初始化等等
- 2敛腌、這里最重要的是
_dyld_objc_notify_register
方法,他這里就是dyld的注冊監(jiān)聽方法卧土,用來跟objc關(guān)聯(lián)的惫皱。
二像樊、dyld和objc關(guān)聯(lián)過程
1、_dyld_objc_notify_register解析
- 1.1 在objc代碼中我們看到它的聲明
//
// 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.
//
void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
_dyld_objc_notify_init init,
_dyld_objc_notify_unmapped unmapped);
不知道大家有沒有注意到源碼中的注釋
+load()
旅敷,這是一個小細節(jié)生棍,初始化鏡像的時候會調(diào)用在鏡像中的+load()
方法.
- 1.2 在這個注釋中說
dyld
將會調(diào)用mapped
、unmapped
媳谁、initialized
這些方法涂滴;既然是dyld
調(diào)用那這些方法就應(yīng)該會傳到dyld
中啊友酱,順著這條思路應(yīng)該能想到_dyld_objc_notify_register
的實現(xiàn)應(yīng)該在dyld
中,果不其然,在dyld3
中
void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
_dyld_objc_notify_init init,
_dyld_objc_notify_unmapped unmapped)
{
log_apis("_dyld_objc_notify_register(%p, %p, %p)\n", mapped, init, unmapped);
gAllImages.setObjCNotifiers(mapped, init, unmapped);
}
2、setObjCNotifiers解析
void AllImages::setObjCNotifiers(_dyld_objc_notify_mapped map, _dyld_objc_notify_init init, _dyld_objc_notify_unmapped unmap)
{
_objcNotifyMapped = map;
_objcNotifyInit = init;
_objcNotifyUnmapped = unmap;
//.....此處省略
}
這三個函數(shù)指針會賦值給_objcNotifyMapped
柔纵、_objcNotifyInit
缔杉、_objcNotifyUnmapped
這三個變量,其實這里就是寫入注冊函數(shù)
3、map_images解析
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_nolock
函數(shù)看看搁料,這里的核心代碼是_read_images
方法
if (hCount > 0) {
_read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
}
- 3.1: 條件控制進行一次的加載
- 3.2: 修復(fù)預(yù)編譯階段的
@selector
的混亂問題 - 3.3: 查找類或详,錯誤混亂的類處理
- 3.4: 修復(fù)重映射一些沒有被鏡像文件加載進來的 類
- 3.5: 修復(fù)一些消息!
- 3.6: 當我們類里面有協(xié)議的時候 : readProtocol
- 3.7: 修復(fù)沒有被加載的協(xié)議
- 3.8: 分類處理
- 3.9: 類的加載處理
- 3.10: 沒有被處理的類 優(yōu)化那些被侵犯的
4、readClass解析
在_read_images
中有一個readClass
方法的調(diào)用;
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
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;
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;
}
這一步會把class信息從二進制里面讀出來郭计,
- 將
newCls->data()
取出來作rw
霸琴; - 將
newCls->data()
再取出來強轉(zhuǎn)為class_ro_t *
放到到rw
的ro
部分 -
addClassTableEntry
這是將類插入到類的集合表中,為了后面調(diào)用的快速查找
三昭伸、總結(jié)
dyld和objc中是存在著一些交互的過程梧乘,需要關(guān)聯(lián)起來進行研究學(xué)習(xí)。