在dyld
加载过程中,我们知道会调用_objc_init
方法,那么在_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);#if __OBJC2__ didCallDyldNotifyRegister = true;#endif}
从_objc_init
实现中我们分析下该方法主要做了什么
该方法主要是读取运行时的环境变量,我们可以通过设置DYLD_PRINT_STATISTICS = YES
来打印APP启动到main()函数之前的时长,进而可以进行APP启动优化。具体的environ_init()简介可参考博客iOS-底层原理 16:dyld与objc的关联中有关nviron_init()
部分的介绍
主要用于关于线程key的绑定,比如每线程数据的析构函数。
void tls_init(void){#if SUPPORT_DIRECT_THREAD_KEYS pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);#else _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);#endif}
主要是C++静态构造函数
static void static_init(){ size_t count; auto inits = getLibobjcInitializers(&_mh_dylib_header, &count); for (size_t i = 0; i < count; i++) { inits[i](); }}
主要是运行时的初始化,主要分为两部分:分类初始化
和类的表初始化
void runtime_init(void){ objc::unattachedCategories.init(32); objc::allocatedClasses.init();}复制代码
初始化libobjc异常处理
/************************************************************************ exception_init* Initialize libobjc's exception handling system.* Called by map_images().**********************************************************************/void exception_init(void){ old_terminate = std::set_terminate(&_objc_terminate);}
主要是缓存初始化
void cache_init(){#if HAVE_TASK_RESTARTABLE_RANGES mach_msg_type_number_t count = 0; kern_return_t kr; while (objc_restartableRanges[count].location) { count++; } kr = task_restartable_ranges_register(mach_task_self(), objc_restartableRanges, count); if (kr == KERN_SUCCESS) return; _objc_fatal("task_restartable_ranges_register failed (result 0x%x: %s)", kr, mach_error_string(kr));#endif // HAVE_TASK_RESTARTABLE_RANGES}
主要用来启动机制回调
/// everything is initialized lazily, but for certain processes we eagerly load/// the trampolines dylib.void_imp_implementationWithBlock_init(void){#if TARGET_OS_OSX // Eagerly load libobjc-trampolines.dylib in certain processes. Some // programs (most notably QtWebEngineProcess used by older versions of // embedded Chromium) enable a highly restrictive sandbox profile which // blocks access to that dylib. If anything calls // imp_implementationWithBlock (as AppKit has started doing) then we'll // crash trying to load it. Loading it here sets it up before the sandbox // profile is enabled and blocks it. // // This fixes EA Origin (rdar://problem/50813789) // and Steam (rdar://problem/55286131) if (__progname && (strcmp(__progname, "QtWebEngineProcess") == 0 || strcmp(__progname, "Steam Helper") == 0)) { Trampolines.Initialize(); }#endif}
主要是dyld
注册 实际代码实现
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);}
从上文正中我们可以看出
mapped
即map_images
init
即load_images
unmapped
即unmap_image
/************************************************************************ 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**********************************************************************/voidmap_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
函数中我们发现map_images_nolock函数
是重点,我们进入map_images_nolock
函数
我们查看代码实现
从截图中我们可以看出_read_images
是我们要重点研究的方法
@selector
的错乱问题readClass
读取出来类的信息注意
在分类处理中主要是通过load_categories_nolock
处理,我们进入load_categories_nolock
函数中
load_categories_nolock
函数static void load_categories_nolock(header_info *hi) { bool hasClassProperties = hi->info()->hasCategoryClassProperties(); size_t count; auto processCatlist = [&](category_t * const *catlist) { for (unsigned i = 0; i < count; i++) { category_t *cat = catlist[i]; Class cls = remapClass(cat->cls); locstamped_category_t lc{cat, hi}; if (!cls) { // Category's target class is missing (probably weak-linked). // Ignore the category. if (PrintConnecting) { _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with " "missing weak-linked target class", cat->name, cat); } continue; } // Process this category. if (cls->isStubClass()) { // Stub classes are never realized. Stub classes // don't know their metaclass until they're // initialized, so we have to add categories with // class methods or properties to the stub itself. // methodizeClass() will find them and add them to // the metaclass as appropriate. if (cat->instanceMethods || cat->protocols || cat->instanceProperties || cat->classMethods || cat->protocols || (hasClassProperties && cat->_classProperties)) { objc::unattachedCategories.addForClass(lc, cls); } } else { // First, register the category with its target class. // Then, rebuild the class's method lists (etc) if // the class is realized. if (cat->instanceMethods || cat->protocols || cat->instanceProperties) { if (cls->isRealized()) { attachCategories(cls, &lc, 1, ATTACH_EXISTING); } else { objc::unattachedCategories.addForClass(lc, cls); } } if (cat->classMethods || cat->protocols || (hasClassProperties && cat->_classProperties)) { if (cls->ISA()->isRealized()) { attachCategories(cls->ISA(), &lc, 1, ATTACH_EXISTING | ATTACH_METACLASS); } else { objc::unattachedCategories.addForClass(lc, cls->ISA()); } } } } }; processCatlist(_getObjc2CategoryList(hi, &count)); processCatlist(_getObjc2CategoryList2(hi, &count));}
从load_categories_nolock
函数实现中,我们可以看到该函数将类
、实例方法
、协议
、属性
、类方法
等再次链接了一次。
dyld_start
调用_objc_init
来初始化,_objc_init
中通过dyld
调用_dyld_objc_notify_register
函数,传入map_images
跟load_images
这两个参数来处理map_images
通过map_images_nolock
函数调用_read_images
函数_read_images
函数中处理类信息、属性、协议、分类等
dyld_start
中,此时dyld
跟objc
关联了起来领取专属 10元无门槛券
私享最新 技术干货