iOS底層原理之—dyld與objc的關聯

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"dyld"}]},{"type":"text","text":"加載過程中,我們知道會調用"},{"type":"codeinline","content":[{"type":"text","text":"_objc_init"}]},{"type":"text","text":"方法,那麼在"},{"type":"codeinline","content":[{"type":"text","text":"_objc_init"}]},{"type":"text","text":"方法中究竟做了什麼呢?我們來探究下。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"_objc_init方法"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"_objc_init方法實現"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"void _objc_init(void)\n{\n static bool initialized = false;\n if (initialized) return;\n initialized = true;\n\n // fixme defer initialization until an objc-using image is found?\n environ_init();\n tls_init();\n static_init();\n runtime_init();\n exception_init();\n cache_init();\n _imp_implementationWithBlock_init();\n\n _dyld_objc_notify_register(&map_images, load_images, unmap_image);\n\n#if __OBJC2__\n didCallDyldNotifyRegister = true;\n#endif\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從"},{"type":"codeinline","content":[{"type":"text","text":"_objc_init"}]},{"type":"text","text":"實現中我們分析下該方法主要做了什麼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"environ_init()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"該方法主要是讀取運行時的環境變量,我們可以通過設置"},{"type":"codeinline","content":[{"type":"text","text":"DYLD_PRINT_STATISTICS = YES"}]},{"type":"text","text":"來打印APP啓動到main()函數之前的時長,進而可以進行APP啓動優化。具體的environ_init()簡介可參考博客"},{"type":"link","attrs":{"href":"https://www.jianshu.com/p/25bcb6540045","title":null},"content":[{"type":"text","text":"iOS-底層原理 16:dyld與objc的關聯"}]},{"type":"text","text":"中有關"},{"type":"codeinline","content":[{"type":"text","text":"nviron_init()"}]},{"type":"text","text":"部分的介紹"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"tls_init()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"主要用於關於線程key的綁定,比如每線程數據的析構函數。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"void tls_init(void)\n{\n#if SUPPORT_DIRECT_THREAD_KEYS\n pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);\n#else\n _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);\n#endif\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"static_init()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"主要是C++靜態構造函數"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"static void static_init()\n{\n size_t count;\n auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);\n for (size_t i = 0; i < count; i++) {\n inits[i]();\n }\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"runtime_init()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"主要是運行時的初始化,主要分爲兩部分:"},{"type":"codeinline","content":[{"type":"text","text":"分類初始化"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"類的表初始化"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"void runtime_init(void)\n{\n objc::unattachedCategories.init(32);\n objc::allocatedClasses.init();\n}\n複製代碼\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"exception_init()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"初始化libobjc異常處理"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"/***********************************************************************\n* exception_init\n* Initialize libobjc's exception handling system.\n* Called by map_images().\n**********************************************************************/\nvoid exception_init(void)\n{\n old_terminate = std::set_terminate(&_objc_terminate);\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"cache_init()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"主要是緩存初始化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"void cache_init()\n{\n#if HAVE_TASK_RESTARTABLE_RANGES\n mach_msg_type_number_t count = 0;\n kern_return_t kr;\n\n while (objc_restartableRanges[count].location) {\n count++;\n }\n\n kr = task_restartable_ranges_register(mach_task_self(),\n objc_restartableRanges, count);\n if (kr == KERN_SUCCESS) return;\n _objc_fatal(\"task_restartable_ranges_register failed (result 0x%x: %s)\",\n kr, mach_error_string(kr));\n#endif // HAVE_TASK_RESTARTABLE_RANGES\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"_imp_implementationWithBlock_init()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"主要用來啓動機制回調"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"/// everything is initialized lazily, but for certain processes we eagerly load\n/// the trampolines dylib.\nvoid\n_imp_implementationWithBlock_init(void)\n{\n#if TARGET_OS_OSX\n // Eagerly load libobjc-trampolines.dylib in certain processes. Some\n // programs (most notably QtWebEngineProcess used by older versions of\n // embedded Chromium) enable a highly restrictive sandbox profile which\n // blocks access to that dylib. If anything calls\n // imp_implementationWithBlock (as AppKit has started doing) then we'll\n // crash trying to load it. Loading it here sets it up before the sandbox\n // profile is enabled and blocks it.\n //\n // This fixes EA Origin (rdar://problem/50813789)\n // and Steam (rdar://problem/55286131)\n if (__progname &&\n (strcmp(__progname, \"QtWebEngineProcess\") == 0 ||\n strcmp(__progname, \"Steam Helper\") == 0)) {\n Trampolines.Initialize();\n }\n#endif\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"dyld與objc關聯"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"_dyld_objc_notify_register(&map_images, load_images, unmap_image)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"主要是"},{"type":"codeinline","content":[{"type":"text","text":"dyld"}]},{"type":"text","text":"註冊 實際代碼實現"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,\n _dyld_objc_notify_init init,\n _dyld_objc_notify_unmapped unmapped)\n{\n dyld::registerObjCNotifiers(mapped, init, unmapped);\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從上文正中我們可以看出"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"mapped"}]},{"type":"text","text":"即"},{"type":"codeinline","content":[{"type":"text","text":"map_images"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"init"}]},{"type":"text","text":"即"},{"type":"codeinline","content":[{"type":"text","text":"load_images"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"unmapped"}]},{"type":"text","text":"即"},{"type":"codeinline","content":[{"type":"text","text":"unmap_image"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"map_images()函數分析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"/***********************************************************************\n* map_images\n* Process the given images which are being mapped in by dyld.\n* Calls ABI-agnostic code after taking ABI-specific locks.\n*\n* Locking: write-locks runtimeLock\n**********************************************************************/\nvoid\nmap_images(unsigned count, const char * const paths[],\n const struct mach_header * const mhdrs[])\n{\n mutex_locker_t lock(runtimeLock);\n return map_images_nolock(count, paths, mhdrs);\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從"},{"type":"codeinline","content":[{"type":"text","text":"map_images"}]},{"type":"text","text":"函數中我們發現"},{"type":"codeinline","content":[{"type":"text","text":"map_images_nolock函數"}]},{"type":"text","text":"是重點,我們進入"},{"type":"codeinline","content":[{"type":"text","text":"map_images_nolock"}]},{"type":"text","text":"函數"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"map_images_nolock"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們查看代碼實現"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/20/203fc78b41fdc4cdb300eb6ac6f9022b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從截圖中我們可以看出"},{"type":"codeinline","content":[{"type":"text","text":"_read_images"}]},{"type":"text","text":"是我們要重點研究的方法"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"_read_images函數分析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"是否是第一次加載"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3b/3bb412bea75aa6b491ec57a9ba936b92.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"修復預編譯時"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"@selector"}]},{"type":"text","text":"的錯亂問題"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9d/9daf187e4a92ac44184a0bc1c2361b33.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"錯誤類處理,通過"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"readClass"}]},{"type":"text","text":"讀取出來類的信息"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/39/39bd3cd13cdfdbdf5a66b5021d3e312f.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"重新設置映射鏡像"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d2/d2b751c9c12e14022aea377e8dd4b434.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"消息處理"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b5/b51413d0898e5f64b0b757d62c19450b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"類中如果有協議,讀取協議"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/dc/dcd7d9a5ee77e49779e21dd3e4efe3a5.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"映射協議"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/0b/0bcb82e36377c586e5a5d527fe2d3ce5.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"加載分類"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/66/668cfae9fba3de8ccae6b4375cb4ca04.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"注意"}]},{"type":"text","text":"在分類處理中主要是通過"},{"type":"codeinline","content":[{"type":"text","text":"load_categories_nolock"}]},{"type":"text","text":"處理,我們進入"},{"type":"codeinline","content":[{"type":"text","text":"load_categories_nolock"}]},{"type":"text","text":"函數中"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"load_categories_nolock"}]},{"type":"text","text":"函數"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"static void load_categories_nolock(header_info *hi) {\n bool hasClassProperties = hi->info()->hasCategoryClassProperties();\n\n size_t count;\n auto processCatlist = [&](category_t * const *catlist) {\n for (unsigned i = 0; i < count; i++) {\n category_t *cat = catlist[i];\n Class cls = remapClass(cat->cls);\n locstamped_category_t lc{cat, hi};\n\n if (!cls) {\n // Category's target class is missing (probably weak-linked).\n // Ignore the category.\n if (PrintConnecting) {\n _objc_inform(\"CLASS: IGNORING category \\?\\?\\?(%s) %p with \"\n \"missing weak-linked target class\",\n cat->name, cat);\n }\n continue;\n }\n\n // Process this category.\n if (cls->isStubClass()) {\n // Stub classes are never realized. Stub classes\n // don't know their metaclass until they're\n // initialized, so we have to add categories with\n // class methods or properties to the stub itself.\n // methodizeClass() will find them and add them to\n // the metaclass as appropriate.\n if (cat->instanceMethods ||\n cat->protocols ||\n cat->instanceProperties ||\n cat->classMethods ||\n cat->protocols ||\n (hasClassProperties && cat->_classProperties))\n {\n objc::unattachedCategories.addForClass(lc, cls);\n }\n } else {\n // First, register the category with its target class.\n // Then, rebuild the class's method lists (etc) if\n // the class is realized.\n if (cat->instanceMethods || cat->protocols\n || cat->instanceProperties)\n {\n if (cls->isRealized()) {\n attachCategories(cls, &lc, 1, ATTACH_EXISTING);\n } else {\n objc::unattachedCategories.addForClass(lc, cls);\n }\n }\n\n if (cat->classMethods || cat->protocols\n || (hasClassProperties && cat->_classProperties))\n {\n if (cls->ISA()->isRealized()) {\n attachCategories(cls->ISA(), &lc, 1, ATTACH_EXISTING | ATTACH_METACLASS);\n } else {\n objc::unattachedCategories.addForClass(lc, cls->ISA());\n }\n }\n }\n }\n };\n\n processCatlist(_getObjc2CategoryList(hi, &count));\n processCatlist(_getObjc2CategoryList2(hi, &count));\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從"},{"type":"codeinline","content":[{"type":"text","text":"load_categories_nolock"}]},{"type":"text","text":"函數實現中,我們可以看到該函數將"},{"type":"codeinline","content":[{"type":"text","text":"類"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"實例方法"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"協議"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"屬性"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"類方法"}]},{"type":"text","text":"等再次鏈接了一次。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"非懶加載類處理"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/17/17d174908c921fe744b4c53aac5e5de0.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"處理沒有使用的類"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/34/34489fdb93dfa6ab0a4052595f7cf929.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"dyld與objc關聯總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"dyld_start"}]},{"type":"text","text":"調用"},{"type":"codeinline","content":[{"type":"text","text":"_objc_init"}]},{"type":"text","text":"來初始化,"},{"type":"codeinline","content":[{"type":"text","text":"_objc_init"}]},{"type":"text","text":"中通過"},{"type":"codeinline","content":[{"type":"text","text":"dyld"}]},{"type":"text","text":"調用"},{"type":"codeinline","content":[{"type":"text","text":"_dyld_objc_notify_register"}]},{"type":"text","text":"函數,傳入"},{"type":"codeinline","content":[{"type":"text","text":"map_images"}]},{"type":"text","text":"跟"},{"type":"codeinline","content":[{"type":"text","text":"load_images"}]},{"type":"text","text":"這兩個參數來處理"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"map_images"}]},{"type":"text","text":"通過"},{"type":"codeinline","content":[{"type":"text","text":"map_images_nolock"}]},{"type":"text","text":"函數調用"},{"type":"codeinline","content":[{"type":"text","text":"_read_images"}]},{"type":"text","text":"函數"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"_read_images"}]},{"type":"text","text":"函數中處理"},{"type":"codeinline","content":[{"type":"text","text":"類信息、屬性、協議、分類等"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當一切準備妥當,則再次返回"},{"type":"codeinline","content":[{"type":"text","text":"dyld_start"}]},{"type":"text","text":"中,此時"},{"type":"codeinline","content":[{"type":"text","text":"dyld"}]},{"type":"text","text":"跟"},{"type":"codeinline","content":[{"type":"text","text":"objc"}]},{"type":"text","text":"關聯了起來"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"資料推薦"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你正在跳槽或者正準備跳槽不妨動動小手,添加一下咱們的交流羣"},{"type":"link","attrs":{"href":"https://links.jianshu.com/go?to=https%3A%2F%2Fjq.qq.com%2F%3F_wv%3D1027%26k%3D5JFjujE","title":null},"content":[{"type":"text","text":"1012951431"}]},{"type":"text","text":"來獲取一份詳細的大廠面試資料爲你的跳槽多添一份保障。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/92/92394154a3e96888899d492b73de1e69.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章