本系列博客是本人的源码阅读笔记,如果有 iOS 开发者在看 runtime 的,欢迎大家多多交流。为了方便讨论,本人新建了一个微信群(iOS技术讨论群),想要加入的,请添加本人微信:zhujinhui207407,【加我前请备注:ios 】,本人博客http://www.kyson.cn 也在不停的更新中,欢迎一起讨论
本文完整版详见笔者小专栏:https://xiaozhuanlan.com/runtime
背景
上一篇文章中,我们清除了Win32的相关逻辑。本篇文章将继续带大家研究_objc_init()
方法,其中可能会涉及到:
- 清理一些与我们理解
_objc_init()
无帮助或者可能导致模糊的代码 - 介绍头文件
objc-private.h
详细
之前的文章我们有说过_objc_init()方法是runtime被加载后第一个执行的方法。这个方法有如下几个函数:
void _objc_init(void)
{
environ_init();
tls_init();
static_init();
lock_init();
exception_init();
_dyld_objc_notify_register(&map_2_images, load_images, unmap_image);
}
其中
environ_init()
方法之前的文章已经有提过
tls_init()
方法这里先不多做介绍,因为涉及的知识面比较广,后面的文章会给于详细解释static_init()
也非常有意思,涉及到mach-o文件的构成,这里先不做过多介绍,后面再解释
lock_init()
从名字可以看出是跟锁相关
exception_init()
跟异常相关
_dyld_objc_notify_register
是这个方法的主角,我们点进去看他的介绍:
本文完整版详见笔者小专栏:https://xiaozhuanlan.com/runtime
意思是dyld专门为runtime设计的方法。关于dyld
这里也先不多做介绍了,后面的文章会详细介绍的。
这里笔者要提醒读者的是:
我们如何找到一个方法的实现
是的,其实不论是在点击lock_init()
还是点击exception_init()
我们很可能点击到错误的实现里。
如图,搜索结果有多个方法,但真正objc_init()调用的下图的
那么为何第一张图的exception_init方法未执行,而第二张的执行了呢,这里我们又看到了一个关键宏:
#if !__OBJC2__
按上一篇的思路,我们继续编写测试程序如下:
int main() {
printf("__OBJC2__: %d\n",__OBJC2__);
}
运行后看到后台有如下输出:
__OBJC2__: 1
Program ended with exit code: 0
笔者没有找到官方的文档对于__OBJC2__
的定义,但从字面意思来看就是判断宏内的代码是不是运行在Objective-C 2.0上的,而大部分iOS开发者都知道,我们目前使用的Objective-C 是 2.0的,因此这个宏返回的是true。
既然知道了这一点,我们可以对文件 objc-exception.mm 做一些删减:
*将#if !__OBJC2__
后面的代码清理掉,结果如下:
推而广之,我们全局搜索#if !__OBJC2__
可以做相似的操作:
其他
全局搜索_objc_init(
可以发现,_objc_init()
方法的定义位于文件 objc-internal.h 中:
// Initializer called by libSystem
OBJC_EXPORT void _objc_init(void)
而lock_init
方法位于 objc-private.h 中:
extern void lock_init(void);
同样的,还有tls_init
位于 objc-private.h 中:
extern void tls_init(void);
objc-private.h 和 objc-internal.h 文件后面这两个文件大家后面会经常接触,这里先有个了解:对,这两个文件很重要。