一赤嚼、_objc_init源碼
_objc_init
也是在 libObjc
的源碼中
void _objc_init(void)
{
static bool initialized = false;
if (initialized) return;
initialized = true;
// fixme defer initialization until an objc-using image is found?
// 讀取影響運行時的環(huán)境變量等孵。如果需要蹂空,還可以打印環(huán)境變量幫助
environ_init();
// 關(guān)于線程key的綁定,比如:線程數(shù)據(jù)的析構(gòu)函數(shù)
tls_init();
// 運行C++靜態(tài)構(gòu)造函數(shù)咐熙。在dyld調(diào)用我們的靜態(tài)構(gòu)造函數(shù)之前棋恼,libc 會調(diào)用 _objc_init()
static_init();
// runtime運行時環(huán)境初始化
runtime_init();
// libobjc異常處理系統(tǒng)初始化
exception_init();
// 緩存條件初始化
cache_init();
// 啟動回調(diào)機制爪飘。通常不會做什么师崎,因為所有的初始化都是惰性的
_imp_implementationWithBlock_init();
/*
_dyld_objc_notify_register -- dyld 注冊的地方
- 僅供objc運行時使用
- 注冊處理程序犁罩,以便在映射床估、取消映射 和初始化objc鏡像文件時使用鬼雀,dyld將使用包含objc_image_info的鏡像文件數(shù)組源哩,回調(diào) mapped 函數(shù)
map_images:dyld將image鏡像文件加載進內(nèi)存時鸦做,會觸發(fā)該函數(shù)
load_images:dyld初始化image會觸發(fā)該函數(shù)
unmap_image:dyld將image移除時會觸發(fā)該函數(shù)
*/
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
#if __OBJC2__
didCallDyldNotifyRegister = true;
#endif
}
_objc_init
這個方法里面基本上本身沒有什么邏輯坛掠,又把邏輯封裝了一下,下面看下里面每個方法的作用
二舷蒲、environ_init() 環(huán)境變量初始化
- environ_init
- Read environment variables that affect the runtime.
- Also print environment variable help, if requested.
【譯】- 讀取影響運行時的環(huán)境變量牲平。
- 如果需要纵柿,還可以打印環(huán)境變量幫助昂儒。
void environ_init(void)
{
// 省略...
// Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
if (PrintHelp || PrintOptions) {
if (PrintHelp) {
_objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
_objc_inform("OBJC_HELP: describe available environment variables");
if (PrintOptions) {
_objc_inform("OBJC_HELP is set");
}
_objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
}
if (PrintOptions) {
_objc_inform("OBJC_PRINT_OPTIONS is set");
}
for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
const option_t *opt = &Settings[i];
if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help);
if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env);
}
}
}
把里面的 for
循環(huán)拿出來放到外面,把判斷條件去掉
for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
const option_t *opt = &Settings[i];
_objc_inform("%s: %s", opt->env, opt->help);
_objc_inform("%s is set", opt->env);
}
運行工程刹枉,會在控制臺輸出如下環(huán)境變量幫助:
objc[15188]: OBJC_PRINT_IMAGES: log image and library names as they are loaded
objc[15188]: OBJC_PRINT_IMAGES is set
objc[15188]: OBJC_PRINT_IMAGE_TIMES: measure duration of image loading steps
objc[15188]: OBJC_PRINT_IMAGE_TIMES is set
objc[15188]: OBJC_PRINT_LOAD_METHODS: log calls to class and category +load methods
objc[15188]: OBJC_PRINT_LOAD_METHODS is set
objc[15188]: OBJC_PRINT_INITIALIZE_METHODS: log calls to class +initialize methods
objc[15188]: OBJC_PRINT_INITIALIZE_METHODS is set
objc[15188]: OBJC_PRINT_RESOLVED_METHODS: log methods created by +resolveClassMethod: and +resolveInstanceMethod:
objc[15188]: OBJC_PRINT_RESOLVED_METHODS is set
objc[15188]: OBJC_PRINT_CLASS_SETUP: log progress of class and category setup
objc[15188]: OBJC_PRINT_CLASS_SETUP is set
objc[15188]: OBJC_PRINT_PROTOCOL_SETUP: log progress of protocol setup
objc[15188]: OBJC_PRINT_PROTOCOL_SETUP is set
objc[15188]: OBJC_PRINT_IVAR_SETUP: log processing of non-fragile ivars
objc[15188]: OBJC_PRINT_IVAR_SETUP is set
objc[15188]: OBJC_PRINT_VTABLE_SETUP: log processing of class vtables
objc[15188]: OBJC_PRINT_VTABLE_SETUP is set
objc[15188]: OBJC_PRINT_VTABLE_IMAGES: print vtable images showing overridden methods
objc[15188]: OBJC_PRINT_VTABLE_IMAGES is set
objc[15188]: OBJC_PRINT_CACHE_SETUP: log processing of method caches
objc[15188]: OBJC_PRINT_CACHE_SETUP is set
objc[15188]: OBJC_PRINT_FUTURE_CLASSES: log use of future classes for toll-free bridging
objc[15188]: OBJC_PRINT_FUTURE_CLASSES is set
objc[15188]: OBJC_PRINT_PREOPTIMIZATION: log preoptimization courtesy of dyld shared cache
objc[15188]: OBJC_PRINT_PREOPTIMIZATION is set
objc[15188]: OBJC_PRINT_CXX_CTORS: log calls to C++ ctors and dtors for instance variables
objc[15188]: OBJC_PRINT_CXX_CTORS is set
objc[15188]: OBJC_PRINT_EXCEPTIONS: log exception handling
objc[15188]: OBJC_PRINT_EXCEPTIONS is set
objc[15188]: OBJC_PRINT_EXCEPTION_THROW: log backtrace of every objc_exception_throw()
objc[15188]: OBJC_PRINT_EXCEPTION_THROW is set
objc[15188]: OBJC_PRINT_ALT_HANDLERS: log processing of exception alt handlers
objc[15188]: OBJC_PRINT_ALT_HANDLERS is set
objc[15188]: OBJC_PRINT_REPLACED_METHODS: log methods replaced by category implementations
objc[15188]: OBJC_PRINT_REPLACED_METHODS is set
objc[15188]: OBJC_PRINT_DEPRECATION_WARNINGS: warn about calls to deprecated runtime functions
objc[15188]: OBJC_PRINT_DEPRECATION_WARNINGS is set
objc[15188]: OBJC_PRINT_POOL_HIGHWATER: log high-water marks for autorelease pools
objc[15188]: OBJC_PRINT_POOL_HIGHWATER is set
objc[15188]: OBJC_PRINT_CUSTOM_CORE: log classes with custom core methods
objc[15188]: OBJC_PRINT_CUSTOM_CORE is set
objc[15188]: OBJC_PRINT_CUSTOM_RR: log classes with custom retain/release methods
objc[15188]: OBJC_PRINT_CUSTOM_RR is set
objc[15188]: OBJC_PRINT_CUSTOM_AWZ: log classes with custom allocWithZone methods
objc[15188]: OBJC_PRINT_CUSTOM_AWZ is set
objc[15188]: OBJC_PRINT_RAW_ISA: log classes that require raw pointer isa fields
objc[15188]: OBJC_PRINT_RAW_ISA is set
objc[15188]: OBJC_DEBUG_UNLOAD: warn about poorly-behaving bundles when unloaded
objc[15188]: OBJC_DEBUG_UNLOAD is set
objc[15188]: OBJC_DEBUG_FRAGILE_SUPERCLASSES: warn about subclasses that may have been broken by subsequent changes to superclasses
objc[15188]: OBJC_DEBUG_FRAGILE_SUPERCLASSES is set
objc[15188]: OBJC_DEBUG_NIL_SYNC: warn about @synchronized(nil), which does no synchronization
objc[15188]: OBJC_DEBUG_NIL_SYNC is set
objc[15188]: OBJC_DEBUG_NONFRAGILE_IVARS: capriciously rearrange non-fragile ivars
objc[15188]: OBJC_DEBUG_NONFRAGILE_IVARS is set
objc[15188]: OBJC_DEBUG_ALT_HANDLERS: record more info about bad alt handler use
objc[15188]: OBJC_DEBUG_ALT_HANDLERS is set
objc[15188]: OBJC_DEBUG_MISSING_POOLS: warn about autorelease with no pool in place, which may be a leak
objc[15188]: OBJC_DEBUG_MISSING_POOLS is set
objc[15188]: OBJC_DEBUG_POOL_ALLOCATION: halt when autorelease pools are popped out of order, and allow heap debuggers to track autorelease pools
objc[15188]: OBJC_DEBUG_POOL_ALLOCATION is set
objc[15188]: OBJC_DEBUG_DUPLICATE_CLASSES: halt when multiple classes with the same name are present
objc[15188]: OBJC_DEBUG_DUPLICATE_CLASSES is set
objc[15188]: OBJC_DEBUG_DONT_CRASH: halt the process by exiting instead of crashing
objc[15188]: OBJC_DEBUG_DONT_CRASH is set
objc[15188]: OBJC_DISABLE_VTABLES: disable vtable dispatch
objc[15188]: OBJC_DISABLE_VTABLES is set
objc[15188]: OBJC_DISABLE_PREOPTIMIZATION: disable preoptimization courtesy of dyld shared cache
objc[15188]: OBJC_DISABLE_PREOPTIMIZATION is set
objc[15188]: OBJC_DISABLE_TAGGED_POINTERS: disable tagged pointer optimization of NSNumber et al.
objc[15188]: OBJC_DISABLE_TAGGED_POINTERS is set
objc[15188]: OBJC_DISABLE_TAG_OBFUSCATION: disable obfuscation of tagged pointers
objc[15188]: OBJC_DISABLE_TAG_OBFUSCATION is set
objc[15188]: OBJC_DISABLE_NONPOINTER_ISA: disable non-pointer isa fields
objc[15188]: OBJC_DISABLE_NONPOINTER_ISA is set
objc[15188]: OBJC_DISABLE_INITIALIZE_FORK_SAFETY: disable safety checks for +initialize after fork
objc[15188]: OBJC_DISABLE_INITIALIZE_FORK_SAFETY is set
找一個 環(huán)境變量 OBJC_PRINT_LOAD_METHODS
: log calls to class and category +load methods
蟋软,記錄對類和類別 + load
方法的調(diào)用
Edit Scheme
設置
在自定義類中岳守,添加 + load
方法
@implementation GLPerson
+ (void)load {}
@end
運行工程:
會發(fā)現(xiàn)湿痢,不管是系統(tǒng)的,還是自定義的類扑庞,所有實現(xiàn) + load
方法的類都會打印出來譬重。
通過終端命令 export OBJC_HELP=1
也可以查看環(huán)境變量幫助
三、tls_init 本地線程池初始化
主要作用是: 本地線程池的初始化和析構(gòu)
罐氨。
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
}
四臀规、static_init 運行C++靜態(tài)構(gòu)造函數(shù)
- 運行
C ++
靜態(tài)構(gòu)造函數(shù)。 -
libc
在dyld
調(diào)用我們的靜態(tài)構(gòu)造函數(shù)之前調(diào)用_objc_init()
栅隐,因此塔嬉,我們必須自己做玩徊。
static void static_init()
{
size_t count;
auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);
for (size_t i = 0; i < count; i++) {
inits[i]();
}
}
五、runtime_init runtime運行時環(huán)境初始化
void runtime_init(void)
{
objc::unattachedCategories.init(32);
objc::allocatedClasses.init();
}
六谨究、exception_init 異常處理系統(tǒng)初始化
初始化 libobjc
的異常處理系統(tǒng)恩袱。由map_images()
調(diào)用
void exception_init(void)
{
old_terminate = std::set_terminate(&_objc_terminate);
}
七俩檬、cache_init 緩存條件初始化
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
}
八冰肴、_imp_implementationWithBlock_init 啟動回調(diào)機制
該方法主要是啟動回調(diào)機制联逻,通常這不會做什么,因為所有的初始化都是惰性的公壤,但是對于某些進程慨飘,我們會迫不及待地加載 libobjc-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_objc_notify_register dyld注冊
// 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);
這個方法本身只是一個注冊函數(shù)的聲明,在 objc
源碼中找不到實現(xiàn)了,具體實現(xiàn)還需去 dyld
源碼中去查看祈匙。
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
傳了3
個參數(shù):
-
map_images
: 引用傳遞,dyld
將image
(鏡像文件)加載進內(nèi)存時,會觸發(fā)該函數(shù); -
load_images
: 值傳遞市埋,dyld
初始化image
會觸發(fā)該函數(shù); -
unmap_image
: 值傳遞褐着,dyld
將image
移除時洋访,會觸發(fā)該函數(shù);