前语

在之前的文章中,咱们介绍了对象的数据,属性办法成员变量等。这些都是经过代码结束,都需求加载到内存中咱们才干运用,要否则只是文件缓存视频在手机哪里找,今日咱们来根究它们是怎样加载到应用程序的。

准备作业

  • objc4-818.2 源码
  • dyl架构师和程序员的差异d-852 源码
  • libdispatch 源码
  • Libsystem 源码

一、应用程序的加载原理

每个应用程序加载都需求一些底层的库,UIKitCoreFoundationAVFoundation等等。是可实施的二进制文件,能被操作体系加载到内存,有静态库动态库

编译进程

iOS 底层原理:应用程序加载

可实施文件

1. 项目工程 可实施文件

创建一个macOS的工程:

int main(int argc, const char * argv[]) {
@autoreleasepo变量类型有哪些ol {
// inse架构师和程序员的差异rt code here...
NSLog(@"Hello, Wo函数调用的三种办法rld!");
}
return 0;
}
  • 代码便是默许的打印缓存视频变成本地视频,不做修改。

接下来生成可实施文件,并拖到termina架构师薪酬一月多少l中:

iOS 底层原理:应用程序加载

  • 如上图,可实施文件拖到终端中是能够实施操作的,打印出了Hello,World!

2. 体系库 可实施文件

查找体系Fo架构规划undation可实施文件:

iOS 底层原理:应用程序加载

  • 经过image list架构师架构工程师取到Foundation可实施文件途径,毕竟在磁盘中成功找到。

静态链接 和 动态链接

iOS 底层原理:应用程序加载

  • 动态函数调用联系图链接办法能够同享动态库,优化了内存空间,所以苹果的库都是动态库。

加载进程

库是经过dyld(动态连接变量值器)加载到内存中来的,整体流程能够用下面的图来表明:

iOS 底层原理:应用程序加载

二、dyld 的引出

咱们先创建一个iOS的工程,在ViewController.m中增加load办法:

@implementation ViewController
+ (void)load{
NSLog(@"%s",__func__);
}
@end

main函数处打一个断点,作业程序:

iOS 底层原理:应用程序加载

  • 程序成功断在了main函数,咱们发现在ma函数调用时所供给的参数能够是in函数之前还调用了一个s函数调用中的参数太少tart函数,那么先增加一个start的符号断点进行调试。

增加start符号断点,再次作业程序:

iOS 底层原理:应用程序加载

  • 增加的start符号断点并没有断住,程序仍是走到了ma变量类型有哪些in函数,说明这些符号断点并不是start的结束。在main函数前+[View架构Controller load]被调用了,那么就在l架构工程师oadios14.7晋级新提示函数调用的三种办法法打一个断点进行调试缓存视频怎样转入本地视频

ViewControllerload办法打断ios是什么意思点,作业程序:

iOS 底层原理:应用程序加载

  • 程序断在load办法后,经过bt打印仓库,在仓库中发现了_dyld_starios模拟器t函数。到这儿也是引出了dyld变量与函数点击 dyld-852 进行源码的下载,接下来进行dyld源码的根究。

三、dyld 流程上

源码中大局查找_dyld_start

iOS 底层原理:应用程序加载

  • 咱们在dyldStart函数调用的三种办法up.s文件中找到了_dyld_start的结束。并且看到了call dyldbootstrap::start这样的代码,dyl架构师和程序员的差异dbootstraios15pC++中的命名空间,说明start的结束在这个命名空间变量与函数下。

dyldbootstrap命名空间中找到start函数:

uintptr_t start(const dyld3::MachOLoaded* appsMachHeader, int argc, const char* argv[],
const dyld3::MachOLoaded* dyldsMaios14.7正式版发布chHeader, uintptr_t* startGlue)
{
...
re架构工程师turn dyld::_main((macho_header*)appsM变量类型有哪些ach缓存Header, appsSlide, argc, arg变量之间的联系v, envp, apple, startGlue);
}
  • 能够函数调用中的参数太少看到st缓存视频怎样转入相册ar架构是什么意思t函数中,返回了_main函数,接下来对_main进行剖析。

四、dyld 流程中的 main 函数主流程

点击进入_main函数:

uintptr_t
_main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
int argcios15, const char* argv[], const char* envp[], const char* apple[],
uintptr_t* startGlue)
{
...
// 整个主程序的一些信息的处理,CPU、架构等
getHostInfo(mainExecutableMH, m架构师和程序员的差异ainExecutableSlide);
// 镜像文件的一些处理
{
__block bool platformFoun变量名d = false;
((d变量的界说yld3::MachOFile*)mainExecutabl架构图eMH)->forEachSupportedPlatfo变量之间的联系rm(^(dyld3::Platform platform, uint32_t minOS, uint32_t sdk) {
if (platformFound) {
halt("MH_EXECUTE binaries may only specify one platform");
}
gProcessIn缓存fo->platform = (uint32_t)platform;
platformFound函数调用句子一般办法为 = true;
});
}
// 途径相关的一些操作
const ch缓存ar*缓存视频怎样转入本地视频 rootPath = _simpl缓存视频兼并e_getenv(envp, "DYLD_函数调用能够出现在表达式中吗ROOT_PATH");
if ( (ro缓存视频怎样转入相册otPath != NULL) ) {
..架构师需求把握哪些常识.
}
else {
...
}
// 同享缓存加载 load shared cache
mapSharedCache(mainExecuta缓存视频怎样转入相册bleSlide)缓存视频在手机哪里找;
// 实例化主程序 instantiate ImageLoader for main executable
sMainExecutable = instant缓存视频怎样转入本地视频iateFromLoadedImag缓存是什么意思e(mainExecutableMH, mainExecutableSlide, sExecPath);
// 加载刺进的动态库 load anios是什么意思y inserted libraries
if	( sEnv.DYLD_IN变量名SERT_LIBRARIES架构规划 != NULL ) {
for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib != NULL; ++lib)
loadIn缓存视频变成本地视频sertedDylib(*lib);
}
// link 主程序
link(sMainExecutable, sEnv.DYLD_BIND_函数调用能够作为一个函数的形参AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL), -1);
// 循环递归绑定 Bind and notify for the inserted imag变量的指针其意义是指该变量的es now interposing has been registered
if ( sInsertedDylibCount > 0 ) {
for(unsigned int i=0; i < sInsertedDylibCount;变量值 ++i) {
ImageLoader* image架构师需求把握哪些常识 = sAllImages[i+1];
image->recursiveBin架构规划d(gLinkContext, sEnv.DYLD_BIND_AT_LAUNCH, true, nullptr);
}
}
// 弱引证绑定主程序 <rdar函数调用句子://problem/12186933> do weak binding only afteriOS all缓存视频兼并 inserted images linked
sMainExecutable->weakBind(gLinkContext);
gLinkCon架构师和程序员的差异text.linios15kingMainExecutable = false;
// 初始化 run all initializers
initializeMainExios是什么意思ecutable();
//函数调用的三种办法 奉告dyld能够进main()函数了 notify any monto变量是什么意思ring proccesses that this process is abo缓存视频变成本地视频ut to enter main()
notifyMonitoringDyldMain();
result = (uintptr_t)sMainExecutable-&架构图gt;getEntryFromLC_UNIXTHREAD();
return result;
}

五、initia缓存的视频怎样保存到本地lizeMainExecut变量名的命名规矩able 流程-主程序作业

进入initializeMainExecutable函数:

void initializeMainExecutable()
{
// ru架构师薪酬一月多少n initialzers for any inserted dylibs
//ios14.4.1更新了什么 allImagesCount():拿到一切镜像文件的个数
ImageLoader:架构:InitializerTimingList initializerTimes[allImagesCount()缓存视频怎样转入相册];
initializios体系erTimes[0].count = 0;
const size_t rootCount缓存 = sImageRoots.size();
if ( rootCount > 1 ) {
for(siz函数调用联系图e_t i=1; i < rootCount; ++i) {
// 镜像文件初始化
sImageRoots[i]->runInitializers(gLinkContext, initializerTimes[0]);
}
}
// 主程序初始化 run initializers for main executable and everything it brings up
sMainExecutable->runInitializers(gLinkContext, initializerTimes[0]iOS);架构图模板
}
  • 能够发现变量的界说不管是镜像文件初始化,仍是主程序的初始化,都是调架构师薪酬一月多少用了runInitializers

runInitializers

进入runInitializ架构图怎样做worders函数:

iOS 底层原理:应用程序加载

  • 这个函数的重点是processInitializers函数。

processInitializers

进入processInitializers函数:

void ImageLoader::processInitializers(c变量名onst LinkContext& context, mach_port_t thisThread,
InitializerTimingList& timingInfo, ImageLoader::UninitedUpwar函数调用联系图ds& images)
{
uint32_t maxImageCount = context.imageCount()+2;
ImageLoad函数调用联系图er::UninitedUpwards upsBuffer[maxImageCount]架构工程师;
ImageLoader::UninitedUpwards& ups = upsBuffer[0];
ups.count = 0;
// Calling recursive init函数调用时所供给的参数能够是 on all images in images lis缓存视频在手机哪里找t, bui缓存lding a new list of
// uninitialized upward dependencies.
for (uintptr_t i=0; i < images.c函数调用中的参数太少ount; ++i) {
images.imagesAndPaths[i].first-&ios下载gt;recursiveInitialization(context, this变量名Thread, imag变量名es.imagesA缓存视频兼并ndPaths[i].second, timingInfo,缓存文件在哪里 ups);
}缓存
// If any upward dependencies remain, init them.
if ( ups.count &gt缓存视频兼并app下载; 0 )
processI缓存视频变成本地视频nitializers(context,架构图 thisThread, t变量类型有哪些imingInfo, ups);
}
  • 这个函数的重点是变量名的命名规矩recursiveInitialization函数。

recursiveInitialization

进入recursiveI缓存视频兼并nitialization函数:

void Imageios下载Loader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread, const char* pathToInitialize,ios14.4.1更新了什么
Initial变量泵izerTimingList& timingInfo, UninitedUpwards& uninitUps)
{
if ( fState < dyld_image_state_dependents_initialized-1 ) {架构
uint8_t oldState = fState架构;
// break cycles
fState = dyld_image_state_dependents_i架构规划nitialized-1;
try {
// initialize lower level libraries first
// 依托文件递归初始化函数调用的一般格式
for缓存文件在哪里(unsigned int i=0; i < libraryCount(); ++i) {
ImageLoader* dependentImage = libImage(i)架构图怎样做word;
if ( dependentImage != NULL ) {
// don't try to initialize架构工程师 stuff "above" me yet
if ( lib变量的界说IsUpward(i) ) {
tUps.imagesios14.7正式版发布AndPaths[uninitUps.counios下载t] = { dependentImage, libPath(i) };
uninitUps.count++;
}
else if ( dependentImage->fD函数调用句子一般办法为epth >= fDepth ) {
dependentImage->recursiveInitialization(context, this_函数调用th变量是什么意思read, libPath(i), timingInfo, uninitUps);
}
}
}
// record termination order
if ( this->needsTermination() )ios14.7正式版发布
context.terminationRecorder(this);
// let函数调用时的实参和形参之间传递 oios模拟器bjc know we are about to initialize this image
uint64_t t1 = mach_absolute_time();
fState = dyld函数调用联系图_image_sta缓存视频兼并te_dependents_initialized;
old架构工程师State = fState缓存文件在哪里;
// 单个奉告注入
context.no函数调用的三种办法tifySingiOSle(dyld_image_state_dependents_initialized, this, &tim函数调用能够作为一个函数的形参ingInfo);
// 调用init办法 initialize thi函数调用时所供给的参数能够是s im缓存视频变成本地视频age
bool hasInitializers = t架构规划his-&gt缓存视频怎样转入本地视频;doInitialization(context);
// let anyone know we fin缓存视频怎样转入相册ished initializing this image
fState = dyld_image_state_initialized;
oldState = fState;
// 奉告初始化结束
context.notifySingle(dyld_image_state缓存的视频怎样保存到本地_in架构师需求把握哪些常识itia缓存文件在哪里lized, this, NULL);
}
catch (const chaios15正式版本什么时候发布r* msg) {
...
}
}
}
  • context.notifySingle:单个奉告注入。
  • this->doInitialization:调用init办法。
  • context.notifySingle:奉告初始化结束。缓存视频变成本地视频

notifySin变量gle

大局查找,找到了notifySingle函数的缓存视频在手机哪里找赋值:

iOS 底层原理:应用程序加载

点进进入notifySingle

static void notifySingle(dyld_变量值image_states state, const ImageLoader* image, ImageLoader::Iios14.7正式版发布nitializerTimingList* timingInfo)
{
//dyld::log("notifySingle(state=%d, image=%s)n", state, image->getPath());
std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sSingleHandlers);
if ( handlers != NULL ) {
dyld_image_info info;
info.imageLoadAd变量类型有哪些dress	= image->缓存视频变成本地视频machHeader();
info.imageFilePath		= image->getRealPath();
info.imageFileModDate	= image->lastModified();
for (std::vector<dyld_im变量之间的联系ag函数调用句子e_state_change_handler>::iterator it = ha架构工程师ndlers->begin缓存视频怎样转入本地视频(); it != handlers->end(); ++it) {
const char* result = (*it)(sta函数调用时的实参和形参之间传递te, 1, &info);
if ( (result != NULL) &&函数调用时的实参和形参之间传递amp; (state == dyld_image_state_mapped) ) {
//fprintf(stderr, "  image rejected by handler=%pn", *it)缓存视频兼并app下载;
// make copy o函数调用能够作为一个函数的形参f thrown string so that later catch clauses can free it
c缓存视频onst c缓存是什么意思har* str = strdup(result);
throw str;
}
}
}
if ( state == dyld_image_state_mapped缓存是什么意思 ) {
// <rdar://problem/7变量的界说008875> Save load addr + UUID for images from outside架构图 the shared cache
// <rdar://problem函数调用时的实参和形参之间传递/50432671> Include UUIDs forios14.7晋级新提示 shared cache dylibs in all image info when using priv架构图怎样做wordate mapp函数调用中的参数太少ed shared caches
if (!image->iios15nSharedCache()
|| (gLinkContext.s缓存的视频怎样保存到本地haredRegionMode == ImageLoader::kUsePrivateSharedRegion)) {
dyld_uuid_info info;
if ( image->getUUID(info.imageUUID) ) {
info.imageLoadAddress = image->machHeader();
addNonSharedCacheImageUUID缓存视频在手机哪里找(info);
}
}
}
if ( (state == dyld_image_state_dependents_initialized) && (sNotifyObjCInit架构工程师 != NULL) &&a缓存的视频怎样保存到本地mp; image->notifyO缓存视频bjC() )缓存视频变成本地视频 {
uint64_t t0 = mach_absolute_time();
dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_I缓存视频兼并app下载NIT, (uint64_t)函数调用句子一般办法为image->machHeader(), 0, 0);
(*sNotifyObjCInit)(image->getRealPath(), image->machHeader());
uint64_t t1 = mach_absolute_time();
uint64_t t2 = mach_absolute_架构工程师time();
uint64_函数调用时所供给的参数能够是t架构图怎样做word timeInOb变量名jC = t函数调用能够作为一个函数的形参1-t0;
u缓存的视频怎样保存到本地int64_t emptyTime = (t2-t架构1)*100;
if ( (timeInObjC > emptyTime) && (timiniOSgInfo != NULL) ) {
timingInfo->addTime(image->getShortName(), timeInObjC);
}
}缓存视频
}
  • 定位要害代码(*sNotifyO函数调用中的参数太少bjCInit)(image->getRealPath(), image->machHeader());

sNotifyObjCInit

查找查找,得到sNotifyObjCInit的相关代码:

static _dyld_objc_notify_init		sNotifyObjCInit;
void registerObjCNotifiers(_dyld_objc_n变量类型有哪些otify_mapped mapped, _dyld_objc_notify_init init, _dyld_objc_notify_unmapped unmapped)
{
// reco函数调用的三种办法rd functions to call
sNotifyOb缓存视频jCMapped	= mapped;
sNotifyObjCInit		= init架构规划;
sNotifyObjCUnmapped = unma架构师需求把握哪些常识pped;
}
  • sNotifyObjCInit_dy缓存视频变成本地视频ld_objc_notify_init类型ios8备忘录的,在registerObjCNotifiers函数中被赋的值,那么registerObjCNotifiers又是在哪儿里被调用的呢。

registerObjCNotifiers

大局查找registerObjCios体系Notifi缓存视频兼并ers函数:

iOS 底层原理:应用程序加载

  • _dyld_objc_notify_register缓存视频兼并app下载数中找到了reg函数调用联系图isterObjCNotifiers的调用,而_dyld_objios是什么意思c_notify_register咱们也是见过的。

看下 objc4-818.2 源码 中 _objc_init缓存视频变成本地视频函数的结束ios14.4.1更新了什么
iOS 底层原理:应用程序加载

  • 在这儿找到了_dyld_objc_notify_registios14.4.1更新了什么er的调用,那么下面咱们以_objc_init为切入点持续根究。

六、images 初始缓存的视频怎样保存到本地化流程

咱们接下来,将以_objc_in架构是什么意思it架构师和程序员的差异切入点,反向推导流程。

翻开 objc4-818.2 源码 ,在_objc_init处打变量泵断点,作业程序:

iOS 底层原理:应用程序加载

  • 能够看到,在函数调用中的参数太少_objc_init函数之前调用了_os_object_ini架构师t,这变量名的命名规矩个函数在libdispatch库中。

_os_object_init

下载 libdispatch 源码 ,在源码中大局查找_os_obj缓存视频兼并ect_init函数:

iOS 底层原理:应用程序加载

  • 找到了_os_object_init函数的结束,并在其中找到了_objc_iiOSnit()函数的调用,现在得到流程:_os_objeios15ct_init -> _objc_ini函数调用句子t()

再看下_os_object_initios8备忘录函数之前调用了什么函数:

iOS 底层原理:应用程序加载

  • 能够看到是libdispatch_in架构工程师it被调用了,它也归于libdios14.4.1更新了什么ispatch库。

libdispat缓存文件在哪里ch_init

大局查找,得到libdispatch_init函数:

libdispatcios14.4.1更新了什么h_init(void)
{
...
_dispatch_hw_config_init();
_dispatch_time_init();
_d缓存视频怎样转入相册ispatch_vtable_init(缓存视频怎样转入本地视频);
_os_object_init();
_voucher_init();
_dispatch_introspection_init();
}
  • libdispat架构师薪酬一月多少ch_init的结束中,找到了_os_object_init()的调用,现在得到变量泵流程:libdispatch_init -> _os_object_init -> _objc_init()

再次剖析仓库,查看libdispat函数调用的三种办法ch_init之前的缓存的视频怎样保存到本地函数调用

iOS 底层原理:应用程序加载

  • libdispatch变量的指针其意义是指该变量的_init之前调用了libSystem_initializer函数,libSystem_initializer归于libSystem库,接下来持续验证。

libSystem_ini架构图模板tializer

下载 Libsystem 源码 ,在源码中大局查找libSystem_i架构图模板nitializer函数:

iOS 底层原理:应用程序加载

  • 找到了libSystem_initializer函数的结束,并在239行找到了libdispatch_init函数的调用,现在得到流程:libSystem_initializer -> libdisp变量的界说atch_init -> _ios下载os_object_init -> _objc_变量之间的联系init()

查看libSyst函数调用联系图em_initializer上一步函数的调用:

iOS 底层原理:应用程序加载

  • 能够看到上一步的调用是doModInitFunctions函数,这次又缓存视频怎样转入相册架构师和程序员的差异到了dyld

doModInitFunctions

找到doModInitFunctions,进入函数:

void ImageLoaderMachO::doModInitFunctions(const LinkContext& c缓存视频ontext)
{
if ( fHasInitializers ) {
const uint32_t cmd_count = ((缓存视频macho_header*)fMachOData)-&g函数调用句子一般办法为t;ncmds;
coiOSnst struct load_command* const cmds = (struct load_command*)&fMachOData[siios14.7晋级新提示zeof(macho_header)];
const structios是什么意思 load_comman变量与函数d* cmd = cmds;
for (uint32_t i = 0; i < cmd_count; ++i缓存视频兼并) {
if ( cmd->cmd == LC_SE缓存视频在手机哪里找GMENT_COMMAND ) {
// macho 中相关 command 的加载
const struct macho_se变量之间的联系gment_command* seg = (struct macho_segment_command*)cmd;
const struct macho_section* const sectionsStartios模拟器 = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
const struct macho_section* const sec架构师需求把握哪些常识tionsEnd = &sectionsStart[seg->nsects];
for (const struct macho_section* sect=sectionsSta函数调用中的参数太少rt; sect < sectionsEnd; ++sect) {
const uios8备忘录int8_t type = sect->flags & SECTION_TYPE;
if ( type == S_MOD_IN变量的指针其意义是指该变量的IT_FUNC_POINTERS ) {
Initializ缓存视频兼并er* iios8备忘录nit函数调用的三种办法s = (Initializer*)(sect->addr + fSlide);
for (size_t j=0; j < coun架构规划t; ++j) {
// 获取各 Initializer 包括 libSystem_initializer
Initializer func =ios15 inits[j];
if ( ! dyld::gProcessInfo->libSystemInitia架构师和程序员的差异lized ) {
// <rdar://prob缓存视频兼并app下载lem/17973316> libSyst架构图怎样做wordem i架构工程师nitializer must run first
// libSystem 有必要最早加载,否则就会报错
const char* inst架构图allPath = getInstallPath();
if ( (installPath == NULL) || (strcmp(installPath, libSystemPath(conte缓存文件在哪里xt)) != 0) )
dyld::throwf(架构是什么意思"initializer in image (缓存的视频怎样保存到本地%s) that d缓存的视频怎样保存到本地oes not link with libSystem.dylibn", this->getPath());
}
bool haveios14.7正式版发布LibSystemHelpersBefore = (dyld::gLibSystemHelpers != NULL);
{
dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER, (uint64_t)fMachOData, (uint64_t)func, 0);
/变量名/ Initializer 包括 libSystem_initializer 的调用
func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
}
if ( !haveLibSystemHelpersios8备忘录Before && haveLibSystemHelpersAf变量的界说ter ) {
// now safe to use malloc(函数调用时的实参和形参之间传递) and other cal变量之间的联系ls in libSystem.dyios14.7正式版发布lib
dyld::gProcessInfo-&gtios15;libSystemInitialized = true;
}
}
}
else if ( type == S_INIT_FUNC_OFFSETS ) {
// 常规的映射等
...
}
}
}
}
}
}
  • 经过函数剖析,能够知道libSystemios体系是第一个会被加载的镜像文件,否则会报错。
  • UIKitFoundation等其他的库,都会依托Runtime的根底、线程的根底、环境根底等,所以要最早加载libSystem
  • Initiali架构zer func = inits[j];第一次获取的func便是libSystem_initializer,并变量的指针其意义是指该变量的经过func(context.argc, context.argv, context.envp, context.apple, &context.programVars);进行调用,接下来查看doModInitFunctions的调用。
  • 现在得到流程:doModInitFunctions -> libSystem_initializer -> libdispatch_in变量的界说it ->架构工程师 _os_object_ini函数调用句子一般办法为t -> _objc_init()

查找doModInitFunctions,查看它的调用:

iOS 底层原理:应用程序加载

  • OK!!,回到了咱们上面说到的函数doInitialization
  • 现在得到流程:doInitialization -> doModInitFunctions -> libSystem_initializer -> libdispatch_init -> _os_object_init -> _objc_initios是什么意思()

七、dyld 链接 objc 的函数实施

经过之前的剖析,咱们得到doIniti变量值alization后边的流程如下:

doInitial架构规划ization -> doModInitFunctions -> libSystem_initializer -> libdispatch_init -> _os_object_init -> _objc_init() -> _dyld_objcios8备忘录_notify_register -> registerObjCNotifiers

再回想下_函数调用的一般格式dyld_objc_notiios体系fy_registerregisterObj架构师薪酬一月多少CNotifiers函数的调用,以及函数结束的要害代码:

void _objc_i函数调用能够作为一个函数的形参nit(void)
{
...
_dyld_objc_notify_register(&map_images, load_images, unmaios15正式版本什么时候发布p_image);
...
}
void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
_dyld_objc_notify_init      init,
_dyld_objc_notify_unmapped  unmapped)
{
d架构是什么意思yld::registerObjCNotifiers(mapped, init, unmapped);
}
void r架构规划egisterObjCNotifiers(_dyld_objc_notify_mapped mapped,
_dyld_o架构是什么意思bjc_notify_init ini变量之间的联系t,
_dyld_objc_notify_unmapped unmapped)
{
// record functions to c变量all
sNotifyObjCMapped	= mapped;
sNotifyObjCInit		= i函数调用的一般格式nit;
sNotifyO缓存的视频怎样保存到本地bjCUnmapped = unma函数调用中的参数太少pped;
...
}
  • 经过比照剖析函数调用的三种办法能够得出,map_images() = sNoios体系tifyOb缓存视频怎样转入相册jCMapped()load_images() = sNotifyObjCInit()
  • 接下来根究一下map_images()load_images()在哪里被调用了。
void ImageLoader::recursive缓存视频兼并app下载In缓存itialization(const LinkContext& cios模拟器ontext, mach_port_t this_thread, const char* pathToInitialize,
InitializerTiminios体系gLios14.4.1更新了什么ist& timingInfo, UninitedUpwards函数调用时所供给的参数能够是& uninitUps)

大局查找sNotifyObjCMapped:函数调用

iOS 底层原理:应用程序加载

  • notifyBatchPartial函数中,找到了sNotifyObjCMapped的调用。

大局查找notifyBatchPar函数调用的一般格式tia缓存视频l:

iOS 底层原理:应用程序加载

  • registerObjCNotifiers函数中找到了notifyBatchP架构工程师artial的调用,本来sNotifyObjC函数调用的一般格式Mapped函数在这个函数中被赋值完,就直接被调用了。

sNotifyObjCInit在哪儿里被调用了呢,持续查找:

iOS 底层原理:应用程序加载

  • notifySingle函数中,ios模拟器找到sNotifyObjCInit的调用。

n变量值otifySingle的调用上面现已聊到过,它和doInitialization相同是在recursiveInitialization中被调用的:

void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thr变量类型有哪些ead, const char* pathToInit架构师和程序员的差异ialize,
InitializerTimingList& timingInfo, UninitedUpwards&a函数调用句子一般办法为mp; uninitUps)
{
if ( fState < dyld_image_state_depeios体系ndents_initialiios14.7晋级新提示zed-1 ) {
try {
// 单个奉告注入
context.notifySi缓存视频怎样转入本地视频ngle(dyld_image_state_dependents_initialized, this, &timingInfo);
// 调用init办法 initialize this image
bool hasInitializers = this->doInitialization(con函数调用中的参数太少text架构规划);
// let anyone know we finished initializing this imag缓存视频变成本地视频e
fSios体系tate变量泵 = dyld_image_state_initialized;
oldState = fState;
// 奉告初始化结束
contex缓存文件在哪里t.notifySingle(dyld_image缓存视频变成本地视频_state_initialized, this, NUios14.4.1更新了什么LL);
}
catch (const ch缓存是什么意思ar* msg) {
...
}
}
}
  • 看代码context.notifySingle是在this函数调用的三种办法->doInitialization前面就被调用了,而sNoti变量fyObjCInit是在doInitialization才被注册,这是为什么呢?
  • 因为recursiveInitialization是个递归函数,第一次调用notifySinglesNotifyObjCInit没有被初始化,第2架构次进来时sNotify变量类型有哪些ObjCInit就有值了。
  • 总结一下,第一次进入时会先调用doInitialization,函数内对mios是什么意思ap_imagesload_images进行初始化,紧接这调用map_i架构图mages。然后走到下面的notifySingle函数,会调用load_images函数。

八、dyld 流程剖析图

iOS 底层原理:应用程序加载

缓存视频兼并app下载日是对dyld的大体流程做了剖析,下一篇将对加载等详细信息进行根究,点个赞支撑一下吧!!。