前沿
我们知道_objc_init是在dyld加载的流程中被调用的, _objc_init到底做了什么呢?
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);
}
environ_init() : 读取影响运行时的环境变量。如果需要,还可以打印环 境变量帮助。
tls_init() 关于线程key的绑定 - 比如每线程数据的析构函数
static_init() 运行C ++静态构造函数。在dyld调用我们的静态构造函数之前,libc
会调用 _objc_init(),因此我们必须自己做
lock_init(): 没有重写,采用C++ 的特性
exception_init () 初始化libobjc的异常处理系统
runtime_init() : runtime运行时环境初始化,里面主要:unattachedCategories,allocatedClasses 后面会分析
cache_init() 缓存条件初始化
_imp_implementationWithBlock_init :启动回调机制。通常这不会做什么,因为所有的初始化都是惰性的,但是对于某些进程,我们会迫不及待地加载trampolines dylib。
environ_init()
在源码environ_init方法中修改一下代码
for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
const option_t *opt = &Settings[I];
_objc_inform("%s is set", opt->env);
}
打印结果
objc[23909]: OBJC_PRINT_IMAGES is set
objc[23909]: OBJC_PRINT_IMAGE_TIMES is set
objc[23909]: OBJC_PRINT_LOAD_METHODS is set
objc[23909]: OBJC_PRINT_INITIALIZE_METHODS is set
objc[23909]: OBJC_PRINT_RESOLVED_METHODS is set
objc[23909]: OBJC_PRINT_CLASS_SETUP is set
objc[23909]: OBJC_PRINT_PROTOCOL_SETUP is set
objc[23909]: OBJC_PRINT_IVAR_SETUP is set
objc[23909]: OBJC_PRINT_VTABLE_SETUP is set
objc[23909]: OBJC_PRINT_VTABLE_IMAGES is set
objc[23909]: OBJC_PRINT_CACHE_SETUP is set
objc[23909]: OBJC_PRINT_FUTURE_CLASSES is set
objc[23909]: OBJC_PRINT_PREOPTIMIZATION is set
objc[23909]: OBJC_PRINT_CXX_CTORS is set
objc[23909]: OBJC_PRINT_EXCEPTIONS is set
objc[23909]: OBJC_PRINT_EXCEPTION_THROW is set
objc[23909]: OBJC_PRINT_ALT_HANDLERS is set
objc[23909]: OBJC_PRINT_REPLACED_METHODS is set
objc[23909]: OBJC_PRINT_DEPRECATION_WARNINGS is set
objc[23909]: OBJC_PRINT_POOL_HIGHWATER is set
objc[23909]: OBJC_PRINT_CUSTOM_CORE is set
objc[23909]: OBJC_PRINT_CUSTOM_RR is set
objc[23909]: OBJC_PRINT_CUSTOM_AWZ is set
objc[23909]: OBJC_PRINT_RAW_ISA is set
objc[23909]: OBJC_DEBUG_UNLOAD is set
objc[23909]: OBJC_DEBUG_FRAGILE_SUPERCLASSES is set
objc[23909]: OBJC_DEBUG_NIL_SYNC is set
objc[23909]: OBJC_DEBUG_NONFRAGILE_IVARS is set
objc[23909]: OBJC_DEBUG_ALT_HANDLERS is set
objc[23909]: OBJC_DEBUG_MISSING_POOLS is set
objc[23909]: OBJC_DEBUG_POOL_ALLOCATION is set
objc[23909]: OBJC_DEBUG_DUPLICATE_CLASSES is set
objc[23909]: OBJC_DEBUG_DONT_CRASH is set
objc[23909]: OBJC_DISABLE_VTABLES is set
objc[23909]: OBJC_DISABLE_PREOPTIMIZATION is set
objc[23909]: OBJC_DISABLE_TAGGED_POINTERS is set
objc[23909]: OBJC_DISABLE_TAG_OBFUSCATION is set
objc[23909]: OBJC_DISABLE_NONPOINTER_ISA is set
objc[23909]: OBJC_DISABLE_INITIALIZE_FORK_SAFETY is set
我们可以在Edit Scheme->Run->Arguments->Enviroment Variables 增加OBJC_PRINT_LOAD_METHODS为YES
打印结果
objc[25298]: LOAD: category 'CIFilter(Interposer)' scheduled for +load
objc[25298]: LOAD: +[CIFilter(Interposer) load]
objc[25298]: LOAD: class 'NSApplication' scheduled for +load
objc[25298]: LOAD: class 'NSBinder' scheduled for +load
objc[25298]: LOAD: class 'NSColorSpaceColor' scheduled for +load
objc[25298]: LOAD: class 'NSNextStepFrame' scheduled for +load
objc[25298]: LOAD: category 'NSColor(NSUIKitSupport)' scheduled for +load
objc[25298]: LOAD: +[NSApplication load]
objc[25298]: LOAD: +[NSBinder load]
objc[25298]: LOAD: +[NSColorSpaceColor load]
objc[25298]: LOAD: +[NSNextStepFrame load]
objc[25298]: LOAD: +[NSColor(NSUIKitSupport) load]
objc[25298]: LOAD: category 'NSError(FPAdditions)' scheduled for +load
我们可以通过设置环境变量来让xcode打印我们想要的内容
// xcode-select -p 在控制台上查看环境变量
// export OBJC_HELP=1自测的貌似没打印出来,但是xcode-select -p能打印出来环境变量
runtime_init
void runtime_init(void)
{
objc::unattachedCategories.init(32);
objc::allocatedClasses.init();
}
unattachedCategories:分类处理的初始化
allocatedClasses,A table of all classes (and metaclasses) which have been allocated with objc_allocateClassPair. 一个已用objc_allocateClassPair分配的所有类(和元类)的表。
exception_init
void exception_init(void)
{
old_terminate = std::set_terminate(&_objc_terminate);
}
static void _objc_terminate(void)
{
if (PrintExceptions) {
_objc_inform("EXCEPTIONS: terminating");
}
if (! __cxa_current_exception_type()) {
// No current exception.
(*old_terminate)();
}
else {
// There is a current exception. Check if it's an objc exception.
@try {
__cxa_rethrow();
} @catch (id e) {
// It's an objc object. Call Foundation's handler, if any.
(*uncaught_handler)((id)e);
(*old_terminate)();
} @catch (...) {
// It's not an objc object. Continue to C++ terminate.
(*old_terminate)();
}
}
}
static objc_uncaught_exception_handler uncaught_handler = _objc_default_uncaught_exception_handler;
objc_uncaught_exception_handler
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler fn)
{
objc_uncaught_exception_handler result = uncaught_handler;
uncaught_handler = fn;
return result;
}
我们可以使用NSSetUncaughtExceptionHandler来设置
NSSetUncaughtExceptionHandler(&MyUncaughtExceptionHandler);
接下来我们来分析我们的重头戏_dyld_objc_notify_register,_dyld_objc_notify_register内有两个回调函数,两个回调在dyld的加载调用,在dyld加载流程中我们知道load_images的调用点,现在我们看一下map_images什么时候调用的,
link========>notifyBatch=======>notifyBatchPartial=====>sNotifyObjCMapped
可知map_images是在load_images之前就调用了
map_images
map_images.pngmap_images_nolock中有一个函数arr_init();
void arr_init(void)
{
AutoreleasePoolPage::init();
SideTablesMap.init();
_objc_associations_init();
}
- AutoreleasePoolPage::init();对自动释放池的初始化
- SideTablesMap.init对管理引用计算map初始化
- _objc_associations_init(),对关联对象的散列表进行初始化
read_images
1: 条件控制进行一次的加载if (!doneOnce)
2: 修复预编译阶段的 @selector
的混乱问题 UnfixedSelectors
3: 错误混乱的类处理readClass
4:修复重映射一些没有被镜像文件加载进来的类 remapClassRef
5: 修复一些消息!fixupMessageRef
6: 当我们类里面有协议的时候 : readProtocol
7: 修复没有被加载的协议 remapProtocolRef
8: 分类处理load_categories_nolock
9: 类的加载处理remapClass addClassTableEntry
10 : 没有被处理的类 优化那些被侵犯的类 realizeClassWithoutSwift
网友评论