一、objc
查看objc源码的时候看到了void _objc_init(void)
函数
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
命令看一下堆栈
结合这张图我们得知
_objc_init
调用流程大致为:
dyld的
doModInitFunctions
方法调用libSystem.B.dylib的libSystem_initializer
方法;接着初始化了libdispatch; libdispatch又调用了_os_object_int
,最终来到了_objc_init
- 1、这里其实是各种初始化:环境初始化;静态变量初始化;运行时初始化;异常初始化;cache初始化等等
- 2、这里最重要的是
_dyld_objc_notify_register
方法,他这里就是dyld的注册监听方法,用来跟objc关联的。
二、dyld和objc关联过程
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()
,这是一个小细节,初始化镜像的时候会调用在镜像中的+load()
方法.
- 1.2 在这个注释中说
dyld
将会调用mapped
、unmapped
、initialized
这些方法;既然是dyld
调用那这些方法就应该会传到dyld
中啊,顺着这条思路应该能想到_dyld_objc_notify_register
的实现应该在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;
//.....此处省略
}
这三个函数指针会赋值给_objcNotifyMapped
、_objcNotifyInit
、_objcNotifyUnmapped
这三个变量,其实这里就是写入注册函数
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
函数看看,这里的核心代码是_read_images
方法
if (hCount > 0) {
_read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
}
- 3.1: 条件控制进行一次的加载
- 3.2: 修复预编译阶段的
@selector
的混乱问题 - 3.3: 查找类,错误混乱的类处理
- 3.4: 修复重映射一些没有被镜像文件加载进来的 类
- 3.5: 修复一些消息!
- 3.6: 当我们类里面有协议的时候 : readProtocol
- 3.7: 修复没有被加载的协议
- 3.8: 分类处理
- 3.9: 类的加载处理
- 3.10: 没有被处理的类 优化那些被侵犯的
4、readClass解析
在_read_images
中有一个readClass
方法的调用;
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()
再取出来强转为class_ro_t *
放到到rw
的ro
部分 -
addClassTableEntry
这是将类插入到类的集合表中,为了后面调用的快速查找
三、总结
dyld和objc中是存在着一些交互的过程,需要关联起来进行研究学习。