前语
在之前的文章中,咱们介绍了对象
和类
的数据,属性
、办法
、成员变量
等。这些都是经过代码结束,都需求加载到内存中咱们才干运用,要否则只是文件缓存视频在手机哪里找,今日咱们来根究它们是怎样加载到应用程序的。
准备作业
- objc4-818.2 源码
- dyl架构师和程序员的差异d-852 源码
- libdispatch 源码
- Libsystem 源码
一、应用程序的加载原理
每个应用程序加载都需求一些底层的库,UIKit
、CoreFoundation
、AVFoundation
等等。库
是可实施的二进制文件,能被操作体系加载到内存,有静态库
和动态库
。
编译进程
可实施文件
1. 项目工程 可实施文件
创建一个macOS
的工程:
int main(int argc, const char * argv[]) {
@autoreleasepo变量类型有哪些ol {
// inse架构师和程序员的差异rt code here...
NSLog(@"Hello, Wo函数调用的三种办法rld!");
}
return 0;
}
- 代码便是默许的打印缓存视频变成本地视频,不做修改。
接下来生成可实施文件,并拖到termina架构师薪酬一月多少l
中:
- 如上图,可实施文件拖到
终端
中是能够实施操作的,打印出了Hello,World!
。
2. 体系库 可实施文件
查找体系Fo架构规划undation
可实施文件:
- 经过
image list架构师
获架构工程师取到Foundation
可实施文件途径,毕竟在磁盘中成功找到。
静态链接 和 动态链接
- 动态函数调用联系图链接办法能够同享动态库,优化了内存空间,所以苹果的库都是动态库。
加载进程
库是经过dyld
(动态连接变量值器)加载到内存中来的,整体流程能够用下面的图来表明:
二、dyld 的引出
咱们先创建一个iOS
的工程,在ViewController.m
中增加load
办法:
@implementation ViewController
+ (void)load{
NSLog(@"%s",__func__);
}
@end
在main
函数处打一个断点,作业程序:
- 程序成功断在了
main
函数,咱们发现在ma函数调用时所供给的参数能够是in
函数之前还调用了一个s函数调用中的参数太少tart
函数,那么先增加一个start
的符号断点进行调试。
增加start
符号断点,再次作业程序:
- 增加的
start
符号断点并没有断住,程序仍是走到了ma变量类型有哪些in
函数,说明这些符号断点并不是start
的结束。在main
函数前+[View架构Controller load]
被调用了,那么就在l架构工程师oadios14.7晋级新提示
方函数调用的三种办法法打一个断点进行调试缓存视频怎样转入本地视频。
在ViewController
的load
办法打断ios是什么意思点,作业程序:
- 程序断在
load
办法后,经过bt
打印仓库,在仓库中发现了_dyld_starios模拟器t
函数。到这儿也是引出了dyld
,变量与函数点击 dyld-852 进行源码的下载,接下来进行dyld
源码的根究。
三、dyld 流程上
源码中大局查找_dyld_start
:
- 咱们在
dyldStart函数调用的三种办法up.s
文件中找到了_dyld_start
的结束。并且看到了call dyldbootstrap::start
这样的代码,dyl架构师和程序员的差异dbootstraios15p
是C++
中的命名空间,说明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
函数:
- 这个函数的重点是
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 >缓存视频兼并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->缓存视频怎样转入本地视频;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
函数的缓存视频在手机哪里找赋值:
点进进入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
函数:
- 在
_dyld_objc_notify_register
函缓存视频兼并app下载数中找到了reg函数调用联系图isterObjCNotifiers
的调用,而_dyld_objios是什么意思c_notify_register
咱们也是见过的。
看下 objc4-818.2 源码 中 _objc_init缓存视频变成本地视频
函数的结束ios14.4.1更新了什么:
- 在这儿找到了
_dyld_objc_notify_registios14.4.1更新了什么er
的调用,那么下面咱们以_objc_init
为切入点持续根究。
六、images 初始缓存的视频怎样保存到本地化流程
咱们接下来,将以_objc_in架构是什么意思it
为架构师和程序员的差异切入点,反向推导流程。
翻开 objc4-818.2 源码 ,在_objc_init
处打变量泵断点,作业程序:
- 能够看到,在函数调用中的参数太少
_objc_init
函数之前调用了_os_object_ini架构师t
,这变量名的命名规矩个函数在libdispatch
库中。
_os_object_init
下载 libdispatch 源码 ,在源码中大局查找_os_obj缓存视频兼并ect_init
函数:
- 找到了
_os_object_init
函数的结束,并在其中找到了_objc_iiOSnit()
函数的调用,现在得到流程:_os_objeios15ct_init
->_objc_ini函数调用句子t()
。
再看下_os_object_initios8备忘录
函数之前调用了什么函数:
- 能够看到是
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
之前的缓存的视频怎样保存到本地函数调用:
-
libdispatch变量的指针其意义是指该变量的_init
之前调用了libSystem_initializer
函数,libSystem_initializer
归于libSystem
库,接下来持续验证。
libSystem_ini架构图模板tializer
下载 Libsystem 源码 ,在源码中大局查找libSystem_i架构图模板nitializer
函数:
- 找到了
libSystem_initializer
函数的结束,并在239
行找到了libdispatch_init
函数的调用,现在得到流程:libSystem_initializer
->libdisp变量的界说atch_init
->_ios下载os_object_init
->_objc_变量之间的联系init()
。
查看libSyst函数调用联系图em_initializer
上一步函数的调用:
- 能够看到上一步的调用是
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 = §ionsStart[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->ios15;libSystemInitialized = true;
}
}
}
else if ( type == S_INIT_FUNC_OFFSETS ) {
// 常规的映射等
...
}
}
}
}
}
}
- 经过函数剖析,能够知道
libSystemios体系
是第一个会被加载的镜像
文件,否则会报错。 -
UIKit
、Foundation
等其他的库,都会依托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
,查看它的调用:
-
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_register
和registerObj架构师薪酬一月多少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
:函数调用
- 在
notifyBatchPartial
函数中,找到了sNotifyObjCMapped
的调用。
大局查找notifyBatchPar函数调用的一般格式tia缓存视频l
:
- 在
registerObjCNotifiers
函数中找到了notifyBatchP架构工程师artial
的调用,本来sNotifyObjC函数调用的一般格式Mapped
函数在这个函数中被赋值完,就直接被调用了。
sNotifyObjCInit
在哪儿里被调用了呢,持续查找:
- 在
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
是个递归函数,第一次调用notifySingle
时sNotifyObjCInit
没有被初始化,第2架构次进来时sNotify变量类型有哪些ObjCInit
就有值了。 - 总结一下,第一次进入时会先调用
doInitialization
,函数内对mios是什么意思ap_images
和load_images
进行初始化,紧接这调用map_i架构图mages
。然后走到下面的notifySingle
函数,会调用load_images
函数。
八、dyld 流程剖析图
今缓存视频兼并app下载日是对dyld
的大体流程做了剖析,下一篇将对类
加载等详细信息进行根究,点个赞支撑一下吧!!。