iOS 类加载流程分析(上)

  上篇文章咱们现已剖析了运用程序的加载流程,关于运用程序的加载流程咱们现已很了解了,咱们现已清楚的理解了在ObjC源码中_objc_init函数接口卡中调用dyld库的函数_dyld_objc_not接口类型ify_register时所传入的两个函数map_images以及load_imAPPages的调用流程,load_im工商管理ages其实便是调用了OC类及其分类中重写的loadswift世界结算体系办法,可是swift怎样读map_images这个函数的调用做了些什么呢?咱们现在变量名并不清楚,因而接下来的要害便是要去根究map_images这个变量类型有哪些函数中的代码逻辑,让咱们一同来看看吧!

本节要害

ObjC环境变量的打印以及运用

ObjC异常处理

read_Images函数流程根究

1. _objc_init函数代码解析

接口是什么 在根究map_images函数代码逻辑之前,首要来根究一下_objc_init中的函数调用都做了些什么吧,说不定与map_images接口类型数调用有关,其代码如下所示:

v变量oid _objc_init(void)
{
static bool initialized = fal变量与函数se;
if (initialized) return;
initialized = true;appointment
// fixme defer initialization until an objc-using i狗狗币mage is founswiftcode是什么意思中文d?
environ_init();
tls_init();
static_init();
runtime_init();
exception_init();狗狗币
#if __OB变量名的命名规矩JC2__
cache_t::init();
#endGoif
_imp_implementationWithBlock_init();
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
#if __OBJC2__
didCallDyldNotifyRegister = true;
#endif
}

  _objc_init函数中首要界说了一个部分的静态变狗狗币量,假定初始化过,下次再次调用_objc_init这个函数时就会直接回来,保证_obj变量的界说c_init函数中调用的其他函数只会被实施一次。

1.1枸杞 environ_init函数

  咱们先来看看envir接口的界说on_init函数中都做接口和抽象类的差异了些什么操作,其代码如下所示:

/***********************************************************************
* environ_init
* Read environment variables that affect the runtime接口文档.
* Also print environment variable help, if requested.
************************************app下载******appstore***********application***********swifter******/
void environ_init(vo接口文档id)
{
ifappear (issetugid()) {
// All environm变量的指针其意义是指该变量的enswiftlyt variables ar接口的界说e silently igapplenored when setuid or setgid
// This includeswift代码s OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
return;
}
// Turn off autorelease变量名 LRU coalescing by default for apps linked against
// older SDKs. LRU coalescing接口的界说 can reorder releases and宫颈癌 cert宫颈癌ain olappleder apps
// are accidentally relying on the ordering.
// rappledar://problem/63886091
//    if (!dyld_program_sdk_at_least(d变量yld_接口是什么fall_2020_os_veapplicationrsions))
/接口测验面试题/        DisableAutoreleaseCappleoalescingLRU = true;
bool PrintHe接口和抽象类的差异lp = false;
boo工程造价l PrintOptions = false;
bool maybeMallocDebugging = false;
// Scan environ[] directly instead of callingapplication getenv() a lot.
// This optimizes the case where none are set.
for (char **p = *_NSGetEnviron(); *p != nil; p++) {
if (0 == strncmp(*p, "Malloc", 6)  ||  0 == strncmp(*p, "DYLswiftkeyD", 4)  ||
0 == strncmp(*p, "NSZombiesEnabled", 16))
{
maybeMallocDebugging = true;
}
if (0 != strnc变量名mp(*p, "OBJC_", 5)) continue;
if (0 == strncmp(*p, "OBJC_HELP=", 10)) {
PrintHelp = true;
continue;
}
if (0 == strncmp(*appointmentp, "OBJC_PRINT_OPTIONS=", 19)) {appear
PrintOptions = true;
continue;
}
if (0 == strncmp(*p, "狗狗币OBJC_DEBUG_POOL_DEPTH=", 22)) {
SetPageCountWarning(*approachp +宫颈癌 22);
continue;
}
const char *value = strcswift世界结算体系hr(*p, '=');
if (!*value) continue;
value++;
for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
const opswiftlytion_t *opt = &Settings[i];
if ((size_t)(value - *p) == 1+opt-swift代码>envlswiftlyen  &&
0 == strncmp(*p, opt->env, opt->envlen))
{
*opt->var = (0 == strcmp(value, "YES"));
break;
}
}
}
// Speciswiftcode是什么意思中文al case: enable some autorelease pool debugging
// when some malloc debugging is enabled
// and OBJC_DEBUG_POOL_ALLOCATION is not set to something ot接口文档her than NO.
if (maybeMalloc狗狗币Debugging) {
const char *insert = g变量名的命名规矩etenv("DYLD_INSERT_LIBRARIES");
const char *zombie = getenv("NSZomb变量名的命名规矩iesEnabled");
cons接口测验面试题t char变量名 *pooldebug = getenv("OBswiftcode代码查询JC_DEBUG_POOL_ALLOCATION工商银行");
if ((getenv("MallocStackLoggappetiteing")
|| getenv("MallocStackLoggingNoCompact")
|| (zombie && (*zombie == 'Y' || *zombie == 'appreciatey'))
|| (insert &am变量值p;&amswift体系p; strstr(insert, "libswiftcode是什么意思中文gmalloc")))
&&
(!pooldebug || 0 == strcmp(pooldebug, "YES")))
{
De接口测验面试题bugPoolAllocation = true;
}
}
//    if (!os_feature_enabled_simp变量值le(objc4, preoptimizedCaches, true)) {
//        DisablePr宫颈癌eoptCaches = true;
//    }
// Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
if (PrintHelp  ||  PrintOptio接口测验面试题ns) {
if (Print变量与函数Help) {
_objc_inform("Objective-C runtime debugging. S接口测验面试题et variable=YES to enable.");
_objc_inform("OBJC_HELP: describe avaiswift代码lable接口卡 e接口的界说nviron变量的界说ment variables");
if (PrintOptions) {
_objc_Swiftinform("OBJC_HELP is set");
}
_objc_inform("OBJC_PRINT_OPTI接口卡ONS: lis接口测验t which op变量名tions are set");
}
if (PrinswiftkeytOptions) {
_objc_inform("OBJC_PRINT_OapplePTIONS 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) _o变量的指针其意义是指该变量的bjc_inform("%s is set", opt-&g公积金t;env);
}
}
}

  依据注释信息咱们可知这个函数是用来初始化环境变量的,能够读取影响作业时的环境变量,假定发送相关恳求,也能够打印环境接口类型变量帮忙,可是咱们并不知道怎样发送这些恳求,此刻就能够将下面的代码段(也便是终究一个for循环的代码拷贝出来将其间的if判别句子去除后的代码接口的界说)拷贝到if句子外面,如下图所示:

iOS 类加载流程剖析(上)

  编译作业ObjC源码,就能够看到如下的打印信息:

objc[9899]: OBJC_PRINT_IMAGES: log image and library names as they are loaapplicationded
objc[9899]: OBJC_PRINT_IMAGES is set
objc[9899]: OBJC_PRINT_IMAGE_TIMES: measure duration of image loadin接口和抽象类的差异g ste工商银行ps
objc[9899]: OBJC_PRINT_IMAGE_TIMES is set
objc[9899]: OBJC_PRINT_LOAD_METHODS: log calls to clappreciateass and caapp是什么意思tegory +load methods
objc[9899]: OBJC_PRINT_LOAD_METHODS is set
objc[9899]: OBJC_PRINT_INIT宫颈癌IALIZE_METHODS: log calls to class +initialize methods
objc[approach9899]: OBJC_PRswift代码是什么意思INT_INITIALIZE_METHODS is set
objc[9899]: OBJC_PRINTappointment_RESOLVED_METHODS: log methods created by +resolveClassMetho接口文档d: and接口测验 +resolv工商银行eInstanceMethod:
objc[9899]:变量之间的联系 OBJC_PRINT_RESOLVED_METHODS is seswift怎样读t
objc[989swift体系9]: OBJC_PRINT_CLASS_SETUP: log progress of class and category setup
ob变量值jc[宫颈癌前期症状9899]: OBJC_PRINT_CLASS_SETUP is set
objc[9899]: OBJC_PRINT_PROTOCOL_SETUP: log progswift世界结算体系ress of protocol setapproachup
objc[9899]: OBJC_PRINT_PROTOCOL_SETUP is set
objc[9899]: OBJC_PRINT_IVAR_SETUP: log processing of non-fragile ivars
objc[9899]: OBJC_PRINT_IVAR_SETUP is set
objc[9899]: OBJC_PRINT_VTABLE_SETUP: log processing of class vtables
objc[9宫颈癌899]: OBJC_PRINT_VTABLE_SETUP is seswift代码是什么意思t
objc[9899]: OBJC_PRINT_VTABLE_IMAGES: print vtable images showing overridden methods
obj公积金c[9899]: O宫颈癌BJC_PRINT_VTABLE_IMAGES is狗狗币 set
objc[9899]: OBJC_PRINT_CACHE_SETUP: log processing of m接口和抽象类的差异ethod cachesapplication
objc[9899]: OBJC_PRINT_CACHE_SETUP is set
objc[9899]: OBJC_PRINT_FUTURE_CLASSES: log use of future classes for toll-free bridging
objc[9899]: OBJC_PRINT_FUTURE_CLASSES is set
objc工商管理[9899]: OBJC_PRINT工商管理_PREOPTIMIZATION: log preoptimSwiftization courtesy of dyld shared cache
objc[9899]: OBJC_PRINT_PREOPTIMIZATION is set
objc[9899]: OBJC_PRINT_CXX_CTORS: log calls to C++ ctors and dtors for instance variables
objc[9899]: OBJC_PRINT_CXX_CTORS i接口是什么s set
objc[9899]: OBJC_PRINT_EXCEPTIONS: log exception handling
objc[9899]: OBJC_PRINT_EXCEPTIONS is set
objc[9899]: OBJC_PRINT_EXCEPTION_THROW: log backtrace of every objc_excswiftereption_throw()
objc[9899]: OBJC_PRINT_EXCEPTION_THROW is set
objc[9899]: OBJC_PRINT_ALT_HA变量名NDLERS: log processing of exception alt handlers
objc[9899]: OBJC_PRIappleNT_ALT_HANDLERS is set
objc[9899]: OBJC_PRINT_REPLACED_MEappetiteTHODS: log methods replac工商银行ed by变量与函数 category im变量与函数plementations
objc[9899]: OBJCswiftcode是什么意思中文_PRINT_REPLACED_METHODS is set
objc[9899]: OBJC_PR接口INT狗狗币_DEPRECATION_WARNINGS: warn about c变量泵alswift代码是什么意思ls to deprecated runtime functions
objc[9899]: OBJC_PRINT_DEPRECATION_WARNINGS is set
objc[9899]: OBJC_PRINT_POOL_HIGHWATER: log high-water marks for autorelease pools
objc[9899]: OBJC_PRI变量的界说NT_POOL_HIGHWATER is set
objc[9899]: OBJC_宫颈癌前期症状PRINT_CUSTOM_CORE: log classes with custom core methods
objc[9899]: OBJC_PRINT_CUSTOM接口和抽象类的差异_CORE is set
objc[接口测验9899]: OBJC_PRINT_CUSTOM_RR: log claapp下载sses with custom retain/release methods
objc[9899]:application OBJC_PRINT_CUSTOM_RR is set变量泵
objswiftlyc[9899]: OBJC_PRINT_CUSTOM_AWZ: log classapplicationes with custo工商银行m allocWithZone methods
objc[9899]: OBJC_PRINT_CUSTOM_AWswift体系Z is set
objc[9899]: OBJC_PRINT_RAW_ISA: log classes that require raw pointer isa fields工程造价
objc[9899]: OBJC_PRINT_RAW_ISA is set
objc[9899]: O龚俊BJC_DEBUG_UNLOAD: warn about poorly-behaving bundles when unloaded
objc[Go9899]: OBJC_DEBUG_UNLOAD is set
objc[9899]: OBJC_DEBUG_FRAGILE_SUPERCLASSES: warn about subclasses that may have been broken by subsequent changes to superclasses
objc[989工商管理9]: OBJC_DEBUG_FRAGILE_SUPERCLASSES is set
objc[9899]: OBJC_DEBUG_NIL_SYNC:app是什么意思 warn about @synchronized(nil), which does no synchronizat变量与函数ion
objc[9899]: OBJC_DEBUG_NIL_SYNC is set
objc[9899]: OBJC_DEBUG_NONFRAGILE_IVARS: capriciously rearran工商银行ge non-fragile ivars
objc[9899]: OBJC_swift代码是什么意思DEBUG_NONFRAGILE_swift怎样读IVARS is set
objc变量的指针其意义是指该变量的[变量与函数9899]: OBJC_DEBUG_ALT_HANDLERS: record more info abswift代码是什么意思out bad alt handler use
objc[9899]: Oswift世界结算体系BJC_DEBUG_ALT_HANDLERS is set
objc[变量与函数9899]: OBJC_DEBUG_MI公积金SSING_POOLS: warn about autore龚俊lease with no pool in place接口文档, which变量的界说 may be a leak
oswifterbjc[9899]: OBJC_DEBUG_MISSING_POOLS is接口和抽象类的差异 s接口是什么et
ob变量与函数jc[9899]: OBJC_DEBUG_POOL_ALLOCATION: halt when autorelease pools are popped out of order, and allow heap dswiftlyebuggers to track autorelease pools
objc[9899]: OBJC_swiftcode代码查询DEBUG_POOL_ALLOCATION is set
objc接口的界说[9899]: OBJC_DEBUG_狗狗币DUPLI工程造价CATE_CLASSES: halt when multiple classes with the same name are present
objc[9899]: OBJC_DEBUG_D变量名的命名规矩UPLICATE_CLASSES is set
objc[9899]: OBJC_接口文档DEBUG_DONT_CRASH: halt the processappstore by exiting instead接口文档 of crashing
objc[9899]: OBJC_DEBUG_DONT_CRASH is set
objc[9899]: OBJC_DEBUG_POOL_DEPTH: log fault when at le接口是什么ast a set number of autorelease pages hswift体系as be接口测验面试题en allocated
objc[9899]变量的界说: OBJC_DEBUG_POOL_DEPTH is set
objc[9899]:接口自动化 OBJC_DISABLE_VTABLES: disable vtable dispatch
objc[Go9899]: OBJC_DI龚俊SABLE_VTABLES is set
objc[9899]: OBJC_DISABLE_变量是什么意思PREOPTIMgoogleIZATION: disable preoptimization courtesy of dyld shared cache
objc[9899]: OBJC_DISABLE_PREOPTIMIZATION is set
objc[9899]: OBJC_DISABLEapple_TAGGED_POI变量值NTERS: disable tagged pointer optimization of NSNumber et al.
obapplejc[9899]接口自动化: OBJC_DISABLE_TAGGED_POINTERS is set
objc[9899]: OBJC_DISABLE_TAG_OBFUSCATION: disable obfuscation of tagged pointers
objc[9899]: OBJC_DISABLE_TAG_OBFUSCATION is set
objc[98接口99]: OBJC_DISABLE_NONPOINTER_变量是什么意思ISA: disable non-po宫颈癌前期症状inte工商银行r isa fields
objc[9899]: OBJC_DISABLE_NONPOINTER_ISA is set
obswiftcode是什么意思中文jc[9899]: OBJC_DISABLE_INITIALIZE_工商银行FORK_SAFETY: disable safety checks for +initialize after fork
objc[9899]: OBJC_DISABLE_INITIALIZE_FORK_SAFETY is set
objc[9899]: OBJC_swiftkeyDISABLE_FAULTS: disable os f变量值aults
objc[9899]: OBJC_DISABLE_FAULTS is set
objc[9899]: OBJC_DISABLE_PREOPTIMIZED_CACHES: disable preoptimi公积金zed caches
objc[app下载9899]: OBJC_DISABLE_PREOPTIMIZED_C接口crc过错计数ACHES is set
objc[app下载9899]: OBJC_DISABLE_AUswiftcode是什么意思中文TORELEASE_COALESCING: disable coalescing of autorelease po变量名ol pointers
objc[9899]: OBJC_DISABLE_AUTORELEASE_COALESCING is set
objc[9899]: OBJC_DISABLE_AUTORELEASE_COALES变量的界说CING_LRU: disable coalescing of autorelease pool pointers using look back N stappetiterategy
objc[9899]: OBJC_DISABLE_AUTORELEASE_swift怎样读COALESCING_LRU is set

  经过打印咱们能够看到这些环境变量的名字,假定你在主工程中设置这些环境变量就能够依据提示获取到相关信息或许改动某些数据结构,例如:咱们随意创立一个iOS工程,其间创立一个继承自NSObjectPerson类,结束Person类中的类办法loaapp下载d,并设置2个环境变量OBJC_DISABLE_NONPOINTER_ISA(是否禁用NONPOINTER_ISA)设置为NOOBJC_PRINT_LOADapple_METHODS(是否接口测验打印输出LOAD办法调用时的信息)设置为NO,如下图所示:

iOS 类加载流程剖析(上)

  在ViewControllerViewDidLoad办法中编写swiftly代码并打上断点,链接真机,作业程序,打印p政策的isa,发现此isaNONPOINTER_ISA,过掉断点,程序溃散,如下图所示:

iOS 类加载流程剖析(上)

  将OBJC_DISABLE_NONPOINTER_ISAswifter以及OBJC_PRINT_LOAD_METHODS设置为YES,如下APP图所示:

iOS 类加载流程剖析(上)

  编译作业程序,打印输出p政策的isa,如下图所示:

iOS 类加载流程剖析(上)

  OBJC_PRINT_LOAD_METHODS这个环境变量能够appointment输出悉数调用load类办法的类信息,帮忙咱们排变量名查主程序以及framework中调用load的类都有approach哪些,也能够运用终端指令(expor接口的界说t OBJC_HELP=1)打印输出ObjC中的环境变量,如下图所示:

iOS 类加载流程剖析(上)

1.2 environ_init与static_init函数

  tls_iappreciatenit():关于线程key的绑定(比如appear每个线程数据的析构函数),其代码如下所示:

void tls_init(void)
{
#if SUPPORT_DIRECT_THREAD_KEYS
pthread_key_init_np(TLS_DIRECT_KEY, &APP_objcappear_pthread_destroyspecific);
#else
_objc_pthread_key = t接口的界说ls_create(&_ob变量类型有哪些jcappetite_pthread_destroyspecific);
#endif
}

  static_init():作业C++静态结构函数,在appointmentdyld调用咱们的静态结构函数之前,libc会调用_objc_init(),因而咱们有必要自己调用一遍,其代码如下所示:

/********接口自动化*******************************************接口测验面试题**********swift体系**********
* static_接口自动化init
* Run C++ static constructor functions.
* lib变量值c calls _oAPPbjc_swiftkeyinit() before dyld would call our static constructors,
* so we接口文档 have to do it ourselves.
**********************************************app下载************************/
static void s变量是什么意思tswift代码是什么意思atic_init()
{
size_t count;
auto inits = getLibobjcInitializers(&ampswift怎样读;_mh_dylib_header, &count);
for (size_t i = 0; i < count; i++) {
inits[i]();
}
auto offsets = getLibobjcInitializerOffsets(&a接口是什么mp;_mh_dylib_header, &count);
for (size_t i = 0; i &l接口t; count; i++) {
UnsignedInitializer init(offsets[i]);
init();
}
}

1.3APP exception_init函数

  exception_init():初始化libobjc的异常处理体系接口类型,其代码如下所示:

/***********************************swiftcode是什么意思中文***************接口文档*********************
* exc接口文档eption_init
* Initialize接口测验 libobjc's exception handling system.
* Called bappointmenty map_images().
********接口测验面试题***************************application***************************接口类型********/
void exception_init(void)
{
old_terminate = std::set_terminate(&_objc_terminate);
}

  而_objc_termi工程造价nate这个函数狗狗币的代码如变量名的命名规矩下所示:

/************Go******app是什么意思**************app下载***************************************
* _objc_terminate
* Custom std::terminate handler.
*
* The uncaught exception callback is implemented as a std::te接口crc过错计数rminate handswift世界结算体系ler.
* 1. Check if there's an active exceptiswift代码on
* 2. If so, check if it's an Objective-C exception
* 3. If so, call our regis接口的界说tered ca接口文档llback with the object.
* 4. Finally, call th接口自动化e previous terminate handler.
*********变量*********Go****************************************************/
static void (公积金*old_terminate)(void) = nil;变量
static void _objc_terminate(void)
{
if (PrintExceptions) {
_objc_inform("EXCEPTIONS: terminating");
}
if (! __cxa_接口测验current_exappleception_typ接口测验e(变量)) {
// 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 objeappetitect. Call Foundatio变量名n's handler, if any.
(*uncaught_handlerswiftkey)((id)e);
(*old_terminate)();
} @catch (...) {
// It's not an objc object. Continue to C++ termin变量名的命名规矩ate.
(*old_terminswift怎样读ate)Swift();
}
}
}

  依据代码及其注释,咱们变量的界说知道假定产生了OC异常,就会调用unappreciatecaught_handler这个句柄函数来处理异常程序,因而咱们大局查找uncaught_handler这个要害字,会发现如下的代码:

/**接口和抽象类的差异**********************************接口*appreciate**********************************
* _ob工商银行jc_default_uncaught_exc变量名的命名规矩eswift代码ption_handler
* Default unc接口的界说aught exception handler. Expected to be overridden by Foundation.
********接口自动化****************************************************appstore****swift代码******/
static void _obj接口卡c_default_uncaappointmentught_exception_handler(id exception)
{
}
static objc_uncaught_exception_handler uncaught_handler = _objc_default_uncaught_exceptionswift代码_handler;

  依据代码以及注释咱们可知,假定不运用Fo接口的界说undation库中的函数对uncau龚俊ght_handler这个句柄进行重写掩盖,它将会被默认赋值为_objc_default_uncaught_exception_handler这个静态函数的地址,因而咱们再大局查找看看没有有函数对u工程造价nca工程造价ught_handler这个句柄进行赋值,以便找到相关的函数调用,找到相关代码如下所示:


/**********************************接口文档*************************************
* objc_setUncaught变量ExceptionHan变量dler
* Set a handler for uncaught Ob宫颈癌前期症状jective-C exceptions.
* Returns the prappreciateevious handler.
*********************************************appreciate*************************/
objc_uncaught_exception变量名_ha接口卡ndleapp是什么意思r
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler fn)
{
objc_uncaught_exception_handler result = uncaught_handler;
uncaught_handler = fn;
return resuGolt;
}

  咱们在objc_setUncaughtExceptionHandler函数中会对uncaught_handler这个句柄赋值,看到objc_setUncaughtExceptionHa变量名ndler这个函数,咱们能够很天然想到OCNSSetUncaughtExceptionHandler这个函数,而objc_setUncaughtExceptionHa接口测验面试题ndler这个函数会不会便是NSSetUncaughtExceptionHandler函数的底层结束呢?

  首要咱们在自己随意创立的iOS工程中的ViewCont变量是什么意思roller.m中编写如下代码:

#import "ViewController.h"
@interface ViewController ()
@property (nonaswift代码tomic, strong) NSArray *dataArray;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.dataArray = @[@"appstore哈哈", @"呜呜", @"呦呦", @"swiftly嘎嘎"];
}
- (IBAc变量之间的联系tion)buttonClick接口的界说:(idswiftly)sender {
NSLog(google@"%@", self.SwiftdataA接口文档rray[5]);
}
@end变量值

  此刻假定咱们点击按钮,就会抛出数组访问越界的异常而且溃散,如下图所示:

iOS 类加载流程剖析(上)

  可是咱们也能够自己来捕获处理这些异常的信息,创立一个用来捕获处理异常的类Uncaugh公积金tExceptionHandle,如下所示:

iOS 类加载流程剖析(上)

  其代码如下所示:

//UncaughtExceptionHandle.h 文件中代码如下
#import &ltapplication;Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@in接口和抽象类的差异terface UncaughtExceptioappetitenHandle : NSObject
+ (void)installUncaughtSignalExceptionHandler;
@end
NS_ASSUME_NONNULL_END
//UncaughtExceptionHandle.m 文件中代码如下
#imapproachport "UncaughtExceptionHandle.h"
#include <libkern/OSAtom狗狗币ic.h>
#include <execinfo.h>宫颈癌前期症状
#include &lswift世界结算体系t;stdatomic.h&gt接口类型;
//异常名
NSStringswift代码 * const kUncaughtExceptionHandlerSignalExceptionName = @"LGUncaughtswiftcode是什么意思中文ExceptionHandlerSignalExceptionName";
//异常原因
NSString * const kUncaughtExceptionHandlerSignalExcepti接口自动化onReason接口crc过错计数 = @"LGUncaughtExceptionHandlerSignalExceptionReason";
//异常签名
NSString * const kUncaughtExceptionHandlappleerSignalKey = @"UncaughtExceptionHandlerSignalKey";
//异常产生地址(仅有)
NSString * const kUncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey";
//异常保存文件名
NSString * const kUnca枸杞ughtExceptionHandlerFil变量泵eKey = @"Unc变量之间的联系aughtExceptionHandlerFileKey";
//异常函数调用符号信息
NSStriappearng * const kUncaughtExceptionHandlerCallStaappetiteckSymbolsKey = @"UncaughtExceptionHandlerCallStackSymbolsKey";
//atomic_int在库stdatomic中界说
atomic_int      kUncaughtExceptionCount = 0; // 未捕获的异常数量
//
const int32_t   kUncaughtExceptionMaximum = 8公积金; //未捕获的异常数量的最大apple值
//从仓库信息读取信息的开端方位,值为4是由于要越变量泵过UncaughtExceptionHandle调用办法以及函数的仓库信息
const NSInteger kUncaughtExceptionHandlerSkipAddressCount = 4;
//从仓库信息读取信息的数量,获取5个就能够了
const NSInteger kUncaughtExceapp下载ptionHandlerReportAddressCount = 5;
@implementation公积金 UncaughtExceptionHandle
//变量与函数异常处理的函数
void ExceptionHandlers(NSException *exceptioapp下载n) {
NGoSLog(@"%s", __func__);
//获取异常的数量
int32_t exceptionCount = atomic_fetch_add_explicit(&kUncaughtExceptionCount, 1, memory_order_relaxe变量名的命名规矩d);
//接口测验面试题异常数量大于最大值,就不处理了。
if (exceptionCount > kUncaughtExceGoptionMaximum) {
return;
}
//获取仓库信息 -app下载 model 编程思维
NSArray *callStack = [UncaughtExceptionHandle backtrace];
NSMutableDictionary *userInfo = [NSMutswift怎样读ableapp下载Dictionaappetitery dictionaryWithDictionary:[exception userInfo]];
NSLog(@"异常名: %@", exception.name);
NSLog(@"异常原因: %@", exception.工商银行reason);
NSLog(@"异常调用栈信息: %@", exception.callStackSymbols);
[userInfo setObject:exception.name forKey变量类型有哪些:kUncaughtExcept变量ionHandlswiftcode代码查询erSignalExceptionName];
[userInfo setObject:exception.callStackReturnAddresses forKey:kU工商管理nc接口的界说aughtExceptionH宫颈癌and宫颈癌lerSignalExceptionReason];
[userInfo接口测验 setObject:callStack forKey:kUncaughtException接口和抽象类的差异HandlerAddressesKey]swift代码;
[userappstoreInfo setObject:exception.callStackSymbols forKey:kUncaughtExceptionHandlerCallStackSymbolsKey];
[user接口卡Info setObject:@"Dem接口的界说oApp_Exceptions" forKey:kUncaughtExceptionHandlerFileKey];
//保存溃散日志或上传到服务器
[[[UncaughtExceptionHandle alloc] init] performSelectorOnMainThread:@selector(handleExceptiswift代码on:) withObject:[NSException exceptionWithName:[exceptioapp下载n name] reason:[exception reason] userInfo:userInfo] waiswift代码是什么意思tUntilDone:YES];
}
- (void)h变量泵andleException:(NSException *)exception {
NSDictionary *变量之间的联系userInfo = [exception userInfoappear];
//保存本地并上传到服务器
[self saveCrash:exception file:[userInfo obje接口ctForK狗狗币ey:kUncaughtExceptionHandlerFileKey]];
//在这儿也可弹出提示框提示用户相关信息
}
- (void)saveCrash:(NSException *)exception fswifterile:(NSString *)fileName {
//获取发application送异常的仓库信息
Nswift怎样读SArray *stackArray = [[exception userInfo] objectForKey:kUncau宫颈癌ghtExceptionHandlerCallStackSymbol接口的界说sKey];
//异常称谓
NSString *exapplicationceptionName = [exception name];
//异常接口的界说原因
NSString *exceptionReason = [excepti宫颈癌on re接口和抽象类的差异ason];
//直接运用代码输出溃散信息日志
NSLog(@"crash: %@", exception);
//获取保存到本地的文件途径(沙盒缓存途接口是什么径)
NSString *exceptionFilePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stri接口和抽象类的差异ngByAppendingPathCswifteromponent:fileName];
//假定文件途径不存在,就创立这个途径
if (![[NSFileManager defaultManager] fileExistsAtPath:变量与函数exceptionFilePath])变量类型有哪些 {
[[NSFileManager defaultManager] createDirectoryAtPath:exceptionFilePath withIntermediateDirectories:YES attributes:nil error:nil];
}
//获取失swiftcode代码查询常出现时的时间戳,写到文件名后缀中,以便排序及查阅
NSDate *date = [NSDate dateWithTimeIntervalSinceswifterNow:0];
NSTimeInte接口的界说rval timeIntervswiftlyal = [date timeIntervalSince1970];
NSString *timeString = [NSString stringWithFormat:@"接口类型%f", timeInterval];
NSString *savePath = [exceptionFilePath stringByAppendingFormat:@"/crash-error-%@.log", timeString];
//获取异常信息
NSString *exceptionInfo = [NSString stringWithFormat:@"Exception Reason: %@nException Name: %@nExceptAPPion s枸杞tack: %@", exceptionName, exceptionReason, stackArray接口类型];
//将异常信息保存到途径中
BOOL isSuccess = [exceptionInfo writeToFile:savePath atomically:YES encoding:(NSUTF8StringEncoding) error:nil];
NSLog(@"保存溃散日志 success: %d, %@", is公积金Success, savePath);
}
+ (void)installUncaughtSignalExceptionHandler {
//接口类型objc_setUncaughtExceptionHandler()
NSSetUncaughtExceptionHandler(&ExceptionHandlers);
}
+ (NSArray *)baswiftcode是什么意思中文cktrace {
void * callStack[128];
//用于获取其时线程的函数调用仓库,回来实践获取的指针个数
int frames = backtrace(callSt变量名的命名规矩ack, 128);
//从backtrace函数获取的信息转化为一个字符串数组
char **strs = backtrace_symbols(callStack, frames);
int i;
NSMutableArray *backstrace = [NSMutableArray arrayWithCapacity:frames];
for (i = kUncaughtExceptionHandlerSkipAddressCount; i <接口和抽象类的差异 kUncaughtExceptionHandlerSkipapproachAddressCount + kUncaughtExceptionHandlerAPPReportAddressCount; i++) {
NSString *infoStr =swiftkey [NSapp是什么意思String stringWithUTF8String:strs[i]];
NSLog(@"current idx: %d, %@", i,接口是什么 infoStr);
[backstrace addObject:infoStr];
}
free(strs);
return backstrace;
}
@end
//在运用发起的时分进行调appetite用
- (BOOL)applicapp下载ation:(UIApplicationapplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[LGUncaughtExceptionHswiftcode代码查询andle installUncaughtS接口和抽象类的差异ignalExceptionHandler];
retuappointmentrn YES;
}

  这样,在咱们的程序溃散的时分,就会实施到咱们所编写的crash异常捕获的接口类型代码了,虽然咱们知道了了怎样捕捉异常,可是还有必要知道它是怎样捕获的,其实要害就在于installUncaughtSignalExceptionHandler这个变量之间的联系类办法中的代码是怎样结束的,咱们查看这个函数的办法详情,会发现如下信息:

iOS 类加载流程剖析(上)

  除了以上这些信息,再也找不到其他更多信息了,因而咱们在ExceptionHandlers变量值打上断点,再次编译作业程序,点击按钮,实施到断点,打印函数调用仓库信息,如下图所示:

iOS 类加载流程剖析(上)

  依据打印的信息,整个流程就很清楚了,ObjC中的异常体系首要接口和抽象类的差异会在_objc_init中进行初始化,这样每次有异常的时分都会调用ObjC异常体系中的_objc_terminate(间断作业)函app下载数,假定是OC异常就会调用uncaught_handler这个句柄函数approach,而uncaught_handler这个句柄函数默认设置的是_oappearbjc_default_uncaught_exception_handler这个没有函数体的函数,假定主工程想要对uncaught_handle接口r这个句柄进行赋值,就需求调用NSSetUncaughtExceptionHandler这个函数进行传参赋值,而实践上NSSetUncaughtEswift怎样读xceptionHandler这个函数是CoreFoundation库中所露出的接口,而这个接口在CoreF变量类型有哪些oundation中实践上调用的是ObjC库中的函数objc_setUncaughtE龚俊xceptionHandler,终究依据传入的参数对uncaught_handler进行赋值,这个进程也称为下句柄。

1.4 其他初始化函数

  lock_iniswift体系t():没有重写,选用C++特性。

  runtime_init()runtime作业时环境初始化,里边首要是swift代码unattchedCategories(独立的分类表)初始化、allocatedClasses(已分配空间的类表)初始化,这个在之后的文章中会评论,其代码如下所示:

void runtime_init(void)
{
objc::unattachedCategories.init(32);
objc::allocatedClasses.init();
}

  cache_init():缓存条件初始化,其代码如下所示:

void cache_t::init()
{
#if HAVE_TASKswifter_RESTARTABLE_RANGES
mach_msg_type_number_t count = 0;
kern_return_t kappointmentr;
while (objc_restartableRanges[count].location) {
count++;
}
kr = task_restartable_ranges_regi公积金ster(mach_task_self(),
objc_re变量名startableRanges, count);
if (kr == KERN_SUCCESS) return;
_objc_fatal("task_restartable_ranges_register failed (res变量之间的联系ult 0x%x: %s)",
kr, mach_error_变量与函数string(kr));
#e接口的界说ndif // HAVE_TASK_RESTARTABLE_RANGES
}

  _imp_implementationWithBlock_init():发起回调机制,一般这不会做什么,由于悉数的初始化都是慵懒的,可是关于默写进程,咱们会刻不容缓地加载trampolines dylib,其代码如下所示:

/// Initialize the trampoline machinery. Normally this does nothing, as
/// 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-tramp工程造价olines.dylib in certainappreciate processes. Some
// programs (most notably QtWebEngine工商银行Process use变量之间的联系d by older versions变量的指针其意义是指该变量的 of
// embedded Chromium) enable a highly restrictive sandbox profile wh工商银行ich
// blocks access to that dylib. If anythswiftcode是什么意思中文ing calls
// imp_implementationWithBlock (as AppKit has stswiftcode是什么意思中文arted doing) then we'l接口是什么l
// crash trying to load it. Loading it here sets it up before the sandbox
// profile is ena接口的界说bled and blocks it.
//
// This fixes EA Origin (rd接口和抽象类的差异ar://problem/50813789)
// and Steam (rdar://problem/55286131)
if (__progname &&
(strcmp(__progname, "QtWebEnginePr变量与函数ocess") == 0 ||
strcmp(__progname,狗狗币 "Ste宫颈癌am Helper") == 0)) {
Trampolines.Initialize();swift代码是什么意思
}
#endif
}

2. map_images函数代码流程解析

  经过以上的根究咱们对_objc_i接口测验nit中的代码逻辑现已有了很透彻的了解,紧接着咱们就来根究一下map_images函数接口的界说中的逻辑结束,其代码如下所示:

/***********************************************************************
* map_images
* Proc变量之间的联系ess the接口卡 given images wappreciatehich are being mapped in by dyld.
* Calls ABAPPI-agnosswift体系tic code after taking ABI-specific locks.
*
* Locking: write-locks runtimeLockSwift
*******************approach***************************************************/
void
map_images(unsigned couappetitent, const char * const paths[],
const struct mach_header * const mhdrs[])
{
mutex_locker_t lock(runtimeLock);
return map_images_nolock(count, paths, mhdrs);
}

  在函数中又调用了map_images_nolock函数,其代码如下图所示:

iOS 类加载流程剖析(上)

  在这个函数中有157行代码,仍是比较长的,而且这个函数没有回来值,那么咱们只能大约阅读一下整个函数,发现了_read_images(读取程序二进制文件)这个函数,咱们猜测这个函数中应该包含了重要的功能,因而咱们点击查看这个函数的结束,变量名的命名规矩这个函数变量中的代码也是十分长的,有360行代码,而且相同没有回来值,其代码概要如下图所示:

iOS 类加载流程剖析(上)

appreciate 在这个函数中,前面都是关于架构的分类处理,而appreciate咱们真实需求关心的便是每个FixUp以及关于类的加载的代码,因而咱们来进行逐个剖析。

2.1appointment 条件操控进接口测验面试题行一次加载

代码如下:

// This is a misnomer: gdb_objc_工商管理reappointmentalized_classes is actually a list of
// named classegooglesswiftcode是什么意思中文 not in the dyld shared cache, whether realized or not.
// This list excludes lazily named classes, which have to be looked up
// using a getClass hook.
NXMapTable *gdb_objc_realized_classes; // exported for debuggers in objc-gdb.h

  NXMapTable实践上swift代码是一个表,其apple间存放了悉数非懒加载的class,也便是现已结束的类,而且运用getClass进行了Hook

    if (!done接口测验Once) {
doneOnce = YES接口crc过错计数;
launchTime = YES;
...
...
..接口文档.
if (PrintConnecting) {
_objc_inform("CLASS: fo接口und %d c变量名的命名规矩lasses during launch", totalClasses);
}
// namedClasses
// Preoptimized classes doapproachn't go in this table.
// 4/3 is NXMapTable's lappreciateoad factor
//依据其时现已初始化的类的数量计枸杞算出NXCreateMapTable的容量
int namedClassesSize =
(is工商银行Preopt工商管理imswift体系ized工商管理() ? unoptimizedTotaswiftcode代码查询lClasse接口文档s : total接口自动化Classes) * 4 / 3;
gdb_objc_realized_classes =
NXCreateMapTable(NXStrValueMapPrototype, namedClassesSiz工程造价e);
ts.log工程造价("IMAGE TIMES: fswifterirst time tasks"变量名的命名规矩);
}

  app是什么意思在这个函数中调用了NXCreateMapTable函数,其代码如下所示swift怎样读

NXMapTable *NXCreateMapTable(NXMapTabl接口类型ePrototypswiftere prototype, unsigned ca变量的指针其意义是指该变量的pacity) {
retur工程造价n NXCr宫颈癌前期症状eateMapTab接口是什么leFromZone(prototype, capacity, malloc_d公积金efault_zone());
}

  在这个狗狗币函数中创立并回来了NXMapTable类型的表,用来存储非懒加载的类,NXMapTableappointment的创立写在这儿是为了保证这中类型的表只会被创立一次,而之前在_objc_init函数中调用的runtime_init函数中创立的表allocatedClasses实践上存储的是悉数已分配的类(包含元类)宫颈癌,其代码及注释如下所示:

/***********************************************************************
* allocatedClasses
* A table of all classes (and metaclasses) which have been allocated
* with objc_allocateClassPair.
**********************************************************************/
namespace objc {
static ExplicitInitDenseSet<Class> allocatedClasses;
}

2.2 修改预编译阶段@selector的紊乱问题

  代码如下所示:

// Fix up @selector references
sappointmenttatic size_t UnfixedSelectors;
{
mutex_locker_t lock(selLock);
for (EACH_HEADER) {
if (hi->hasPr变量与函数eoptimizedSeapplicationlectors()) continue;
bool isBundle = hi->isBundle();
SEL *s狗狗币els = _gappreciateetObjc2Selecto龚俊rRefs(接口crc过错计数hi, &amp变量;count);
UnfixedSelectors += count;
for (i = 0; i < cappearount; i++) {
const char *name = sel_cname(sels[i]);
SELswift体系 sel = sel_regist工商管理erNameNoLock(name, isBundle);
if (sels[i] != sel) {
sels[i] = sel;
}app是什么意思
}
}
}
ts.log("I变量的指针其意义是指该变量的MAGE TIMES: fix up sswift怎样读electoswiftcode是什么意思中文r references")Swift;

  首要在代码打上接口是什么断点,作业ObjC源码,打印输出下图信息:

iOS 类加载流程剖析(上)

  你会发现sel[i]sel虽然办法编号都是相同的,工程造价可是它们的地址却不相同,可是这儿为什么会将se接口l[i]赋值为sel呢?原因就在于运用_getObjc2SelectorRefs这个函数获取到的sel列表中的每个swiftcode代码查询sel的地址数据实践上是镜像文件中的存储的数据,而镜像文件中的每个sel的地址都是相对与其时镜像文件首Swift地址的偏移值,当这个镜像文件经过ALSR等安全机制加载到内存中后,镜像文件的首appointment地址就会产生随机改动,其间每个sel的地址其实也都产生了改接口测验面试题动,就需求对从镜像文件中宫颈癌前期症状获取到的sel列表中的sel进行rebaseappreciate以获取其此刻此刻在内存中的实践地址,因而sel_registerNameNoLock这个函数便是用来对镜像文件中的sel的地址信息进行rebase操作的,然后将sel赋值给sel[i]

  而sel_regisapproachterNameNoLock这个函数实践上调用的是dyld库中的_dyld_get_objappreciatec_selector函数来获取sel在内存中的swiftly地址的,如下所示:

SEL sel_registerNameNoLock(const变量名 char *name, bool copy) {
return __sel_registerName(name, 0, copy);  // NO lock, maybe copy
}
static SEL __sel_swift怎样读reg接口和抽象类的差异isterName(const char *name, bool shouldLock, bool copy)
{
SEL result = 0;
if (shouldLock) selLock.assertUnlocked();
else selLock.assGoertLocked();
if (!name) return (Sapp下载EL)0;
result = search_builtins(name);
if (result) return result;
conditional_mutex_locker_t lock(seapp是什么意思lLock, shouldLock);
auto it = namedSelectors.get().insert(name);
if (it.接口secondappointment) {
// No match. Insert.
*it.first = (const char *)sel_alloc(name, copy);
}
return (SEL)*it.first;
}
static SEL search_builtins(const char *name)
{
#if SUPPORT_PREOPT
if (SEL result = (SEL)_dyld_get_objc_selector(name))
return result;
#endif
retu公积金rn nil;
}

2.3 差错紊乱的类处理

  代码如下所示:

 //google Discover cgooglelasses. Fix up unresolved future classes. Mark bundle classes.
bool hasDyldRoots = dyld_shared_cache_some_image_overridden();
for (EA变量与函数CH_HEADER) {
if (! mustReadClasses(hi, hasDyldRoots)) {
// Image is sufficswiftkeyiently optimized that we need not caapproachll readAPPClass()
continueapple;
}
classref_t const *classlist = _getObjc2ClassList(hiswiftly, &count);
bool headerIsBapp是什么意思undle = hi->isBundle();
bool headerIsPreo工商管理ptimized = hi-appointment>happetiteasPreoptimize接口测验面试题dClasses();
for (i = 0; i < count; i++) {
Class cls = (Class)classlist[i];
Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
if (newCls != cls  &&  newCls) {
// Class was mov工程造价ed but not deleted变量类型有哪些. Currently this occurs
// only wh接口卡en the new class resolved a future class.
// Non-lazily realize the class below.
resolvedFutureClasses = (Class *)
realloc(resolvedFutureClasses,
(resolvedFutureClassCount+1) * sizeof(Class));
resolvedFutureClasses[resolv宫颈癌edFutureClassCount++] = newCls;
}接口文档
}
}
ts.log("IMAGE TIMES: discover classes接口和抽象类的差异");

  这一部分是对一些在内存中现变量与函数已移动可是还没有删去的类(接口的界说类似于野指针)进行的处理,在这一段代码中咱们发变量的指针其意义是指该变量的现了一个函数readClass,这个函数可能有咱们想要了解的代码逻辑,app是什么意思因而咱们来看看这个函数中的代码,如下所示:

/***********************************swift代码************************************
* readClass
* Read a class and meta变量值class as written bswiftkeyy a compilerswifter.
* Returns the new class point公积金er. This could be:
* - cls
* - nil  (cls has a missing weak-linke接口测验d superclass)
* - something else (space for this class was reserved by a future class)
*
*变量的界说 Note that all work peappstorerformed by this function is preflighted by
* mustReadClasses(). D变量的界说o not change this function without updaswifterting tha变量名t one.
*
* Locking: runti接口的界说meLock acquired by map_images or objc_readClaswiftkeyssPair
***********狗狗币*************************************************appointment**********/
Class reaswift体系dClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
const char *变量名的命名规矩mangledName = cls->nonlazyMangledName()接口文档;
if (missingWeakSuperclass(cls)) {
// No supercappetitelass (probably wswift代码是什么意思eak-linked).
// Disavow any knowledge of this subclass.
if (PrintConnecting) {
_objc_inform("CLASS: IGNO接口crc过错计数RING class '%s' with "
"missing weak-linked supe工商银行rclass",
cls->nameForLogging());
}
addRemappedClass(cls, nil);
cls->setSuperc变量名lass(nil);
retswifterurn nil;
}
cls-app是什么意思>fixupBackwardDeployingStableSwift();
Class rep工程造价lacing = nil;
if (mangledName != nullptr) {
if (Class newCls = popFutureNamedClass(mangledName)) {
// This name was previously allocated as a future class.
// Copapp下载y objc_class to future class's strucGot.
// Preserve future's rw data block.
if (newCls->工商管理isAnySwift()) {
_objc_fatal("Can't complete future class rapplicationequest for '%s' "
"because the real class is too big.",
cls->nameForLogging());
}
class_rw_t *rw = newClswiftlys->data();
const class_ro_t *o变量ld_ro = rw->ro();
memcpy(newCls, cls, sizeof(objc_class));
// Manually se接口crc过错计数t address-discAPPriminated ptrauthed fields
// so that newCls gets the correct signatures.
newCls->setSuperclass(cls->getSuperclass());
newCls->initIsa(cls->getIsa());
rw->set_ro((class_ro_t *)newCls->data());
newCl变量的指针其意义是指该变量的s->setData(rw);
freeI接口测验面试题fMutable((char *)old_ro->getName());
free((void *)old_ro);
addR接口测验emappedClass(cls, newCls);
replacing = cls;
cls = newCls;
}
}
if (headerIsPreoptimized  &&  !replacing) {
// class list buil接口类型t inswift世界结算体系 shared cache
// fixme str变量名的命名规矩ict as接口类型sert doesn't work becswifterause of duplicates
// ASSERT(cls == getClass(name));
ASSERT(mangledName == nullptr || getClassExcep接口tSomeSwift(mangledNa接口类型me));
} else {
if (mangledName) { //applesome Swift generic classes can lazily generappstoreate their names
addNamedClass(cls, mangledName, replacing变量的界说);
} else {
Class meta = cls->ISA();
const class_ro_t *metaRO = meta-&gtapplication;bits.safe_ro();
ASSERT(mswiftlyetaR接口测验面试题O->getNonMetaclass() && "Metaclass with lazy name must have a pointer to the corresponding nonmetaclass.");
ASSERT(metaRO->getNonMetaclass() == cls &变量与函数amp;& "Metaclass nonmetaclass变量的界说 pointer must equal the original class.");
}
addClassTableEntry(cls);
}
// for future reference: shared cache never contains MH_BUNDLEs
if (headerIsBundle)Go {
cls->data()->flags |= RO_FROM_BUNDLE;
cls->ISA()-swifter>data()->flags |= RO_F龚俊ROM_BUNDLE;
}
return cls;
}

  首要这个函数中代码的回来值为cswift世界结算体系ls,因而咱们看看这个函数中有哪些地方对这个cls进行了创立以及操作,咱们发现了咱们所了解的部分,便是对clsrorwrappointmentwe进行赋值操作,而且设置了clsisa以及superclass,如下图所示:

iOS 类加载流程剖析(上)

  但这真的是对class进行加载的代码部分吗?咱们还需求验证一下,咱们在源接口的界说码中创立一个Person类,并在main函数中创立一个Perso接口和抽象类的差异n政策,如下所示:

@interface Person : NSObject
- (voswift怎样读id)say;
@end
@impleme接口文档ntation Person
- (void)say {
}
@end
int main(int a接口是什么rgc, const char * argv[]) {
Person *p = [[Person alloc] init];
@枸杞autoreleasepool {
NSLog(@"实施main函数");
}
return 0;
}

  为了扫除体系类产生的影响,咱们在代码中readCl龚俊ass函数调用之前编swiftcode是什么意思中文写一些代码并设置上断点,如下图所示:

iOS 类加载流程剖析(上)

  编译作业程序,来到断点,打印其时cls,如下所示:

iOS 类加载流程剖析(上)

  然后在re狗狗币adClass变量的界说数中打下如下断点,并单步实施程序,如下所示:

iOS 类加载流程剖析(上)

  单步作业程序,看程序都实施了哪些代码句子,作用如下所示:

iOS 类加载流程剖析(上)

  而是实施了下面所示的宫颈癌分支:

iOS 类加载流程剖析(上)

  实施前后打印cGols龚俊输出作用如下:

iOS 类加载流程剖析(上)

  单步作业,然后实施了addClaswift代码是什么意思ssTablGoeEntry这个函数中的代码,如下图所示:

iOS 类加载流程剖析(上)

  这个函数代码如下所示:

/****接口和抽象类的差异*********************************************************龚俊***宫颈癌******变量与函数*
* add狗狗币ClassTableEntry
* Add a class to the table of all c变量的界说lasses. If addMeta is true,
* automatically adds the metaclass of the class as well.
* Locking: runtimeLock must be held by the caller.
**********************************************************************/
static void
add变量名的命名规矩ClassTableEntr变量名的命名规矩y(Class cls, bool addMeta = true)
{
runtimeLock.assertLocked();
// This class is allowed to be a kno接口的界说wn变量的界说 class via the shared cache or via
// data segments,变量之间的联系 but it is not allowappstoreed to be in the dynamic table already.
auto &set = objc::allocatedClasses.gswiftcode代码查询et();
ASSERT(set.find(cls) == sappetiteet.end());
if (!isKnownClass变量是什么意思(cls))
se接口和抽象类的差异t.insert(cls);
if (addMeta)
addClassTableEntry(cls-工商管理>ISA(), f变量的界说alse);
}

  其逻辑是将cls刺进到已分配类表中,而且还会经过递归调用将其元接口类也刺进到已分配类表中,终究就直接回来了cls,能够发现,关于咱们创立的Personswiftcode是什么意思中文来说,readclass函数仅仅对其类名进行了赋值,并没有为其rorwrwe等其他内容进行赋值。

2.4 修改重映射一些没有被镜像文swifter件加载进来的类

  代码如下所示:

// Fix up remapped classes
// Cl变量之间的联系ass list aswifternd nonlazy class list remain unremapped.
/变量/ Class refs and super refs are remapped for message dispatching.
if (!noClassesRemapped()) {
for (swiftlyEapproachACH_HEADER) {
Class *classrefs = _getObjc2ClassRefs(hi, &count);
for (i = 0; i < count; i++) {
remapClassRef(&classrefs[i]);
}
// fixme why doesn't test future1 catch the absence of this?
cl变量的界说assrefs = _getObjc2SuperRefs(hi, &count);
for (i = 0; i < count; i++) {
remapClassRef(&classrefs[i]);
}
}
}
ts.log("Iapp是什么意思MAGE TIMES: remap classes");

2.5 修改一些消息

  代码如下所示:

#if SUPPORT_FIXUP
// Fix up old objc_msgSend_fixswift代码up call sites
for (EACH_HEADER) {
message_ref_t *refs = _getObjc2MessageappearRefs(hi, &count);
if (count == 0) continue;
if (PrintVtables) {
_objc_inform("VTABLES:swift世界结算体系 repairing %zu unsswiftkeyupported vtable dispatch "
"call sites in %s", count, hi->fname());
}
for (i = 0; i < count; i++) {
fixupMessageRef(refsgoogle+i);
}
}
ts.log("IMAGswiftlyE TIMES: fix up objc_msgSend_fixup");
#endif

3.总结

  异常处理流程图:

iOS 类加载流程剖析(上)

  本篇文章首要根究了在项目开发工程中咱们可能会遇到的一些环境变量以及异常处理的流程,也根究了map_images函数中的代码流程,而map_images流程中重要的函数便是reaapproachd_images函数,而在read_images这个函数中做了许多的修改作业,咱们本来猜测可能是在read_class加载的类的信息,可是咱们调试作业代码的时分,实接口自动化践状况却是仅在read_class接口数中对类名进行了赋值,而且将类参加到了已分配类的表中,由于内容过多,因而将read_images这个函数中的下半部分代码的根究进程放入到下篇文章之application中了,感谢您的阅览!

发表评论

提供最优质的资源集合

立即查看 了解详情