当前位置: 首页 > news >正文

网站搭建是什么专业微信商城系统哪找

网站搭建是什么专业,微信商城系统哪找,地推,做网站公司东莞1.虚拟内存 ASLR 在早期计算机中数据是直接通过物理地址访问的#xff0c;这就造成了下面两个问题 1.内存不够用 2.数据安全问题 内存不够 --- 虚拟内存 虚拟内存就是通过创建一张物理地址和虚拟地址的映射表来管理内存#xff0c;提高了CPU利用率#xff0c;…1.虚拟内存 ASLR 在早期计算机中数据是直接通过物理地址访问的这就造成了下面两个问题 1.内存不够用 2.数据安全问题 内存不够 --- 虚拟内存 虚拟内存就是通过创建一张物理地址和虚拟地址的映射表来管理内存提高了CPU利用率使多个进程可以同时/按需加载。 在iOS中每个进程都有独立的虚拟内存存放物理内存中其地址是从0开始的大小固定4G每个虚拟内存又会按页划分每页16K以页为单位加载每个进程是相互独立的保证进程间的数据安全当一个进程只有部分功能使用时系统会自动将使用部分加载到物理内存中CPU在进行数据访问时会先访问虚拟内存通过虚拟内存和物理内存的映射关系去对应的物理内存中查找在CPU上有专门处理映射的硬件当CPU访问数据时如果虚拟内存中的数据没有物理内存绑定会发生缺页异常pagefault会阻塞当前进程直到数据加载到物理内存中虚拟内存和物理内存绑定当内存条中的内存全部用完后系统会将新的数据覆盖到很久没使用的内存上 数据安全 --- ASLR 因为虚拟内存的起始地址(0x000000)和大小(4G)是固定的这就意味着我们的数据地址也是固定的所以在iOS4.3引进了ASLR。ASLR英文全称Address Space Layout Randomization也叫地址空间配置随机加载是一种针对缓冲区溢出的安全保护技术。通过对堆、栈、共享库映射等线性区布局的随机化增强了攻击者找到目标物理内存的难度防止攻击者直接定位攻击代码位置达到阻止溢出攻击的目的的一种技术。 由于ASLR的存在导致可执行文件和动态链接库在虚拟内存中的地址每次都是不固定的所以需要在编译时来修复镜像中的资源指针来指向正确的地址。即正确的内存地址 ASLR地址 偏移值 2.iOS 系统架构 Mac系统是基于Unix内核的图形化操作系统。Mac OS 和 iOS 系统架构的对比分析发现Mac OS和iOS的系统架构层次只有最上面一层不同Mac是Cocoa框架而iOS是Cocoa Touch框架其余的架构层次都是一样的。 Core OS是用FreeBSD和Mach所改写的一个名叫Darwin的开放原始码操作系统, 是开源、符合POSIX标准的一个Unix核心。这一层包含并提供了整个iPhone OS的一些基础功能比如硬件驱动, 内存管理程序管理线程管理POSIX文件系统网络BSD Socket,以及标准输入输出等所有这些功能都会通过C语言的API来提供。 核心OS层的驱动提供了硬件和系统框架之间的接口。然而由于安全的考虑只有有限的系统框架类能访问内核和驱动。iPhone OS提供了许多访问操作系统低层功能的接口集iPhone 应用通过LibSystem库来访问这些功能这些接口集有线程POSIX线程、网络BSD sockets、文件系统访问、标准I/O、Bonjour和DNS服务、现场信息Locale Information、内存分配和数学计算等。 Core Services在Core OS基础上提供了更为丰富的功能 它包含了Foundation.Framework和Core Foundation.Framework。之所以叫Foundation就是因为它提供了一系列处理字符串排列、组合、日历、时间等等的基本功能。 Foundation是属于Objective-C的APICore Fundation是属于C的API。另外Core servieces还提供了如Security用来处理认证密码管理安全性管理等, Core Location, SQLite和Address Book等功能。 核心基础框架CoreFoundation.framework是基于C语言的接口集提供iPhone应用的基本数据管理和服务功能。该框架支持Collection数据类型Arrays、 Sets等、Bundles、字符串管理、日期和时间管理、原始数据块管理、首选项管理、URL和Stream操作、线程和运行循环Run Loops、端口和Socket通信。 核心基础框架与基础框架是紧密相关的它们为相同的基本功能提供了Objective-C接口。如果开发者混合使用Foundation Objects 和Core Foundation类型就能充分利用存在两个框架中的toll-free bridging技术桥接。toll-free bridging使开发者能使用这两个框架中的任何一个的核心基础和基础类型。 程序启动之前 从应用图标被用户点击开始直到应用可以开始响应发生了很多事情。 很多文章中大家都提到说dyld加载了主程序和动态库这个理解明显是错误的在XNU加载Mach-O和dyld过程中是内核加载了主程序dyld只会负责动态库的加载。虽然主程序也会作为镜像形式被dyld来管理起来。当一个App启动时dyld把App需要的dylib加载进App的内存空间。App运行所需要的信息一般都存放在其MachO头部44中其中dylib的信息是由Load Commands指定的App得到执行时dyld会查看其MachO头部中的Load Commands并把里面LC_LOAD_DYLIB相关的dylib给加载到进程的内存空间。 一般来说逆向工程会在dyld阶段入手之前版本的dyld中确实存在一些漏洞使App能够绕过代码签名例如dyld-353.2.1版本漏洞编号CVE-2015-5876漏洞存在于Mach-O头的处理过程中一个畸形的Mach-O文件可以导致内存段被替换从而导致任意代码执行当然目前dyld的已知漏洞都已修复。监控启动崩溃会在Objc阶段之后具体方法具体分析。 总结来说大体分为如下步骤 (1) 系统为程序启动做好准备。 (2) 系统将控制权交给 DyldDyld 会负责后续的工作。 (3) Dyld 加载程序所需的动态库。 (3) Dyld 对程序进行 rebase 以及 bind 操作。 (4) Objc SetUp。 (5) 运行初始化函数。 (6) 执行程序的 main 函数。 需要注意的是dyld2和dyld3的加载方式略有不同。dyld2是纯粹的in-process也就是在程序进程内执行的也就意味着只有当应用程序被启动的时候dyld2才能开始执行任务。dyld3则是部分out-of-process部分in-process。 dyld2的过程是加载dyld到App进程加载动态库包括所依赖的所有动态库RebaseBind初始化Objective C Runtime和其它的初始化代码。 dyld3的out-of-process会做如下事情分析Mach-O Headers分析依赖的动态库查找需要Rebase Bind之类的符号把上述结果写入缓存。这样在应用启动的时候就可以直接从缓存中读取数据加快加载速度。 从exec()开始 Mach-O是 OS X 系统的可执行文件Mach-O有多种文件类型比如MH_DYLIB文件、MH_BUNDLE文件、MH_EXECUTE文件MH_OBJECT内核加载等。可执行文件离不开进程在 Linux 中我们会通过 Fork()来新创建子进程然后执行镜像通过exec()来替换为另一个可执行程序。在用户态会通过exec*系列函数来加载一个可执行文件。 main()函数是整个程序的入口在程序启动之前系统会调用exec()函数。在Unix中exec和system的不同在于system是用shell来调用程序相当于forkexecwaitpidfork 函数创建子进程后通常都会调用 exec 函数来执行一个新程序而exec是直接让你的程序代替原来的程序运行。 system 是在单独的进程中执行命令完了还会回到你的程序中。而exec函数是直接在你的进程中执行新的程序新的程序会把你的程序覆盖除非调用出错否则你再也回不到exec后面的代码也就是当前的程序变成了exec调用的那个程序了。 UNIX 提供了 6 种不同的 exec 函数供我们使用。 #include unistd.h int execl(const char *pathname, const char *arg0, ... /* (char *)0 */); int execv(const char *pathname, char *const argv[]); int execle(const char *pathname, const char *arg0, ... /* (char *)0, char *const envp[] */); int execve(const char *pathname, char *const argv[], char *const envp[]); int execlp(const char *filename, const char *arg0, ... /* (char *)0 */); int execvp(cosnt char *filename, char *const argv[]); 通过分析我们发现含有 l 和 v 的 exec 函数的参数表传递方式是不同的。含有 e 结尾的 exec 函数会传递一个环境变量列表。含有 p 结尾的 exec 函数取的是新程序的文件名作为参数而其他exec 函数取的是新程序的路径。 如果函数出错则返回-1若成功则没有返回值。其中只有execve是真正意义上的系统调用其它都是在此基础上经过包装的库函数。 exec函数族的作用是根据指定的文件名找到可执行文件并用它来取代调用进程的内容换句话说就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件也可以是任何Unix下可执行的脚本文件。 Dyld Dyld 是 iOS 系统的动态链接器 在dyldStartup.s 文件中有个名为 __dyld_start 的方法它会去调用 dyldbootstrap::start() 方法然后进一步调用 dyld::_main() 方法里面包含 App 的整个启动流程该函数最终返回应用程序 main 函数的地址最后 Dyld 会去调用它。 之后会去加载可执行文件二进制文件常被称为 image包括可执行文件、动态库等ImageLoader 的作用就是将二进制文件加载进内存。dyld::_main() 方法在设置好运行环境后会调用instantiateFromLoadedImage 函数将可执行文件加载进内存中加载过程分为三步 1.合法性检查。主要是检查可执行文件是否合法是否能在当前的 CPU 架构下运行。 2.选择 ImageLoader 加载可执行文件。系统会去判断可执行文件的类型选择相应的 ImageLoader 将其加载进内存空间中。 3.注册 image 信息。可执行文件加载完成后系统会调用 addImage 函数将其管理起来并更新内存分布信息。 以上三步完成后Dyld 会调用 link 函数开始之后的处理流程。 3.静态链接库与动态链接库 iOS中的相关文件有如下几种Dylib动态链接库又称 DSO 或 DLLBundle不能被链接的 Dylib只能在运行时使用 dlopen() 加载可当做 macOS 的插件。Framework包含 Dylib 以及资源文件和头文件的文件夹。 动态链接库是一组源代码的模块每个模块包含一些可供应用程序或者其他动态链接库调用的函数在应用程序调用一个动态链接库里面的函数的时候操作系统会将动态链接库的文件映像映射到进程的地址空间中这样进程中所有的线程就可以调用动态链接库中的函数了。动态链接库加载完成后这个时候动态链接库对于进程中的线程来说只是一些被放在地址进程空间附加的代码和数据操作系统为了节省内存空间同一个动态链接库在内存中只有一个操作系统也只会加载一次到内存中。 因为代码段在内存中的权限都是为只读的所以当多个应用程序加载同一个动态链接库的时候不用担心应用程序会修改动态链接库的代码段。当线程调用动态链接库的一个函数函数会在线程栈中取得传递给他的参数并使用线程栈来存放他需要的变量动态链接库函数创建的任何对象都为调用线程或者调用进程拥有动态链接库不会拥有任何对象。如果动态链接库中的一个函数调用了VirtualAlloc系统会从调用进程的地址空间预定地址即使撤销了对动态链接库的映射调用进程的预定地址依然会存在直到用户取消预定或者进程结束。 静态链接库与动态链接库都是共享代码的方式如果采用静态链接库则无论你愿不愿意lib 中的指令都全部被直接包含在最终生成的包文件中了。但是若使用动态链接库该动态链接库不必被包含在最终包里包文件执行时可以“动态”地引用和卸载这个与安装包独立的动态链接库文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库而在动态链接库中还可以再包含其他的动态或静态链接库。 Linux中静态函数库的名字一般是libxxx.a利用静态函数库编译成的文件比较大因为整个函数库的所有数据都会被整合进目标代码中。编译后的执行程序不需要外部的函数库支持因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点因为如果静态函数库改变了那么你的程序必须重新编译。 动态函数库的名字一般是libxxx.so相对于静态函数库动态函数库在编译的时候并没有被编译进目标代码中你的程序执行到相关函数时才调用该函数库里的相应函数因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序而是程序运行时动态的申请并调用所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序所以动态函数库的升级比较方便。 iOS开发中静态库和动态库是相对编译期和运行期的。静态库在程序编译时会被链接到目标代码中程序运行时将不再需要载入静态库。而动态库在程序编译时并不会被链接到目标代码中只是在程序运行时才被载入因为在程序运行期间还需要动态库的存在。 iOS中静态库可以用.a或.Framework文件表示动态库的形式有.dylib和.framework。系统的.framework是动态库一般自己建立的.framework是静态库。 .a是一个纯二进制文件.framework中除了有二进制文件之外还有资源文件。.a文件不能直接使用至少要有.h文件配合。.framework文件可以直接使用.a .h sourceFile .framework。 动态库的一个重要特性就是即插即用性我们可以选择在需要的时候再加载动态库。如果不希望在软件一启动就加载动态库需要将 Targets--Build Phases--Link Binary With Libraries 中 *.framework 对应的Status由默认的 Required 改成 Optional 或者将 xx.framework 从 Link Binary With Libraries 列表中删除。 可以使用dlopen加载动态库动态库中真正的可执行代码为 xx.framework/xx 文件。 - (IBAction)useDlopenLoad:(id)sender { NSString *documentsPath [NSString stringWithFormat:%/Documents/xx.framework/xx,NSHomeDirectory()]; [self dlopenLoadlib:documentsPath]; }- (void)dlopenLoadlib:(NSString *)path { libHandle NULL; libHandle dlopen([path cStringUsingEncoding:NSUTF8StringEncoding], RTLD_NOW); if (libHandle NULL) {char *error dlerror();NSLog(dlopen error: %s, error); } else {NSLog(dlopen load framework success.); } } 也可以使用NSBundle来加载动态库实现代码如下 - (IBAction)useBundleLoad:(id)sender { NSString *documentsPath [NSString stringWithFormat:%/Documents/xx.framework,NSHomeDirectory()]; [self bundleLoadlib:documentsPath]; }- (void)bundleLoadlib:(NSString *)path { _libPath path; NSError *err nil; NSBundle *bundle [NSBundle bundleWithPath:path]; if ([bundle loadAndReturnError:err]) {NSLog(bundle load framework success.); } else {NSLog(bundle load framework err:%,err); } } 可以为动态库的加载和移除添加监听回调ImageLogger上有一个完整的示例代码从中可以发现一个工程软件启动的时候会加载多达一百二十多个动态库即使是一个空白的项目。 但是需要注意的一点是不要在初始化方法中调用 dlopen()对性能有影响。因为 dyld 在 App 开始前运行由于此时是单线程运行所以系统会取消加锁但 dlopen() 开启了多线程系统不得不加锁这就严重影响了性能还可能会造成死锁以及产生未知的后果。所以也不要在初始化器中创建线程。 据说iOS现在可以使用自定义的动态库低版本的需要手动的使用dlopen()加载。动态库上架会有一些审核的规则如不要把x86/i386的包和arm架构的包lipo在一起使用。如 lipo –create Release-iphoneos/libiphone.a Debig-iphonesimulator/libiphone.a –output libiphone.a 如此便将模拟器和设备的静态库文件合并成一个文件输出了。 dylib加载调用 基于上面的分析在exec()时系统内核把应用映射到新的地址空间每次起始位置都是随机的。然后使用dyld 加载 dylib 文件动态链接库dyld 在应用进程中运行的工作就是加载应用依赖的所有动态链接库准备好运行所需的一切它拥有和应用一样的权限。 加载 Dylib时先从主执行文件的 header 中获取需要加载的所依赖动态库的列表从中找到每个 dylib然后打开文件读取文件起始位置确保它是 Mach-O 文件针对不同运行时可执行文件的文件类型。然后找到代码签名并将其注册到内核。 应用所依赖的 dylib 文件可能会再依赖其他 dylib因此动态库列表是一个递归依赖的集合。一般应用会加载 100 到 400 个 dylib 文件但大部分都是系统 dylib它们会被预先计算和缓存起来加载速度很快。但加载内嵌embedded的 dylib 文件很占时间所以尽可能把多个内嵌 dylib 合并成一个来加载或者使用 static archive。 在加载所有的动态链接库之后它们只是处在相互独立的状态代码签名使得我们不能修改指令那样就不能让一个 dylib 调用另一个 dylib。通过fix-up可以将它们结合起来dyld 所做的事情就是修正fix-up指针和数据。Fix-up 有两种类型rebasing在镜像内部调整指针的指向 和 binding将指针指向镜像外部的内容。 因为地址空间加载随机化的缘故二进制文件最终的加载地址与预期地址之间会存在偏移所以需要进行 rebase 操作对那些指向文件内部符号的指针进行修正。rebase 完成之后就会进行 bind 操作修正那些指向其他二进制文件所包含的符号的指针。因为 dylib 之间有依赖关系所以 动态库中的好多操作都是沿着依赖链递归操作的Rebasing 和 Binding 分别对应着 recursiveRebase() 和 recursiveBind() 这两个方法。因为是递归所以会自底向上地分别调用 doRebase() 和 doBind() 方法这样被依赖的 dylib 总是先于依赖它的 dylib 执行 Rebasing 和 Binding。 Rebaing 消耗了大量时间在 I/O 上在 Rebasing 和 Binding 前会判断是否已经 预绑定。如果已经进行过预绑定Prebinding那就不需要 Rebasing 和 Binding 这些 Fix-up 流程了因为已经在预先绑定的地址加载好了。 Binding 处理那些指向 dylib 外部的指针它们实际上被符号symbol名称绑定是一个字符串。dyld 需要找到 symbol 对应的实现在符号表里查找时需要很多计算找到后会将内容存储起来。Binding 看起来计算量比 Rebasing 更大但其实需要的 I/O 操作很少因为之前 Rebasing 已经替 Binding 做过了。Objective-C 中有很多数据结构都是靠 Rebasing 和 Binding 来修正fix-up的比如 Class 中指向超类的指针和指向方法的指针。 Objc C 会为静态创建的对象生成初始化器与静态语言不同OC基于Runtime机制可以用类的名字来实例化一个类的对象。Runtime 维护了一张映射类名与类的全局表当加载一个 dylib 时其定义的所有的类都需要被注册到这个全局表中。ObjC 在加载时可以通过 fix-up 在动态类中改变实例变量的偏移量利用这个技术可以在不改变dylib的情况下添加另一个 dylib 中类的方法而非常见的通过定义类别Category的方式改变一个类的方法。 Dyld 在 bind 操作结束之后会发出 dyld_image_state_bound 通知然后与之绑定的回调函数 map_2_images 就会被调用它主要做以下几件事来完成 Objc Setup 1.读取二进制文件的 DATA 段内容找到与 objc 相关的信息。 2.注册 Objc 类。 3.确保 selector 的唯一性。 4.读取 protocol 以及 category 的信息。 除了 map_2_images我们注意到 _objc_init 还注册了 load_images 函数它的作用就是调用 Objc 的 load 方法它监听 dyld_image_state_dependents_initialized 通知。 dyld 是运行在用户态的 这里由内核态切到了用户态。每当有新的镜像加载之后都会执行 load-images 方法进行回调这里的回调是在整个Objc runtime 初始化时 -objc-init 注册的。有新的镜像被 map 到 runtime 时调用 load-images 方法并传入最新镜像的信息列表 infoList。调用 prepare-load-methods 对 load 方法的调用进行准备将需要调用 load 方法的类添加到一个列表中)调用 -getObjc2NonlazyClassList 获取所有的类的列表之后会通过 remapClass 获取类对应的指针然后调用 schedule-class-load 递归地 将当前类和没有调用 load 父类进入列表。在执行 add-class-to-loadable-list(cls) 将当前类加入加载列表之前会先把父类加入待加载的列表保证父类在子类前调用 load 方法。在执行 add-class-to-loadable-list(cls) 将当前类加入加载列表之前会先把父类加入待加载的列表保证父类在子类前调用 load 方法。在将镜像加载到运行时、对 load 方法的准备就绪执行 call-load-methods开始调用 load 方法。 由于iOS开发时基于Cocoa Touch的所以绝大多数的类起始都是系统类大多数的Runtime初始化起始在Rebase和Bind中已经完成。 Initializers Objc SetUp 结束后Dyld 便开始运行程序的初始化函数该任务由 initializeMainExecutable 函数执行。整个初始化过程是一个递归的过程顺序是先将依赖的动态库初始化然后在对自己初始化。初始化需要做的事情包括 1.调用 Objc 类的 load 函数。 2.调用 C 中带有 constructor 标记的函数。 3.非基本类型的 C 静态全局变量的创建。 所谓执行监控启动crash的思路都是在这里构建的。下面是一些方法的执行顺序initialize的顺序可能在更早但总是会在load和launch之间。 4.程序启动逻辑 主执行文件和相关的 dylib的依赖关系构成了一张巨大的有向图执行初始化器先加载叶子节点然后逐步向上加载中间节点直至最后加载根节点。这种加载顺序确保了安全性加载某个 dylib 前其所依赖的其余 dylib 文件肯定已经被预先加载。最后 dyld 会调用 main() 函数。main() 会调用 UIApplicationMain()程序启动。 使用Xcode打开一个项目很容易会发现一个文件main.m文件此处就是应用的入口了。程序启动时先执行main函数main函数是ios程序的入口点内部会调用UIApplicationMain函数UIApplicationMain里会创建一个UIApplication对象 然后创建UIApplication的delegate对象 —–您的AppDelegate 开启一个消息循环main runloop每当监听到对应的系统事件时就会通知AppDelegate。 int main(int argc, char * argv[]) {autoreleasepool {return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));} } UIApplication对象是应用程序的象征每一个应用都有自己的UIApplication对象而且是单例的。通过[UIApplication sharedApplication]可以获得这个单例对象一个iOS程序启动后创建的第一个对象就是UIApplication对象利用UIApplication对象能进行一些应用级别的操作。 UIApplicationMain函数实现如下 int UIApplicationMain{int argc,char *argv[],NSString *principalClassName,NSString *delegateClassName} 第一个参数表示参数的个数第二个参数表示装载函数的数组第三个参数是UIApplication类名或其子类名若是nil则默认使用UIApplication类名。第四个参数是协议UIApplicationDelegate的实例化对象名这个对象就是UIApplication对象监听到系统变化的时候通知其执行的相应方法。 启动完毕会调用 didFinishLaunching方法并在这个方法中创建UIWindow设置AppDelegate的window属性并设置UIWindow的根控制器。如果有storyboard会根据info.plist中找到应用程序的入口storyboard并加载箭头所指的控制器显示窗口。storyboard和xib最大的不同在于storyboard是基于试图控制器的而非视图或窗口。展示之前会将添加rootViewController的view到UIWindow上面在这一步才会创建控制器的view [window addSubview: window.rootViewControler.view]; 每个应用程序至少有一个UIWindow这window负责管理和协调应用程序的屏幕显示rootViewController的view将会作为UIWindow的首视图。 程序启动的完整过程如下 1.main 函数。 2.UIApplicationMain a.创建UIApplication对象。 b.创建UIApplication的delegate对象。 delegate对象开始处理(监听)系统事件(没有storyboard) a.程序启动完毕的时候, 就会调用代理的application:didFinishLaunchingWithOptions:方法。 b.在application:didFinishLaunchingWithOptions:中创建UIWindow。 c.创建和设置UIWindow的rootViewController。 d.显示窗口。 4.根据Info.plist获得最主要storyboard的文件名,加载最主要storyboard(有storyboard)。 a.创建UIWindow。 b.创建和设置UIWindow的rootViewController。 c.显示窗口。 AppDelegate的代理方法 //app启动完毕后就会调用 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { }//app程序失去焦点就会调用 - (void)applicationWillResignActive:(UIApplication *)application { }//app进入后台的时候调用 一般在这里保存应用的数据(游戏数据,比如暂停游戏) - (void)applicationDidEnterBackground:(UIApplication *)application { }//app程序程序从后台回到前台就会调用 - (void)applicationWillEnterForeground:(UIApplication *)application { }//app程序获取焦点就会调用 - (void)applicationDidBecomeActive:(UIApplication *)application {}// 内存警告可能要终止程序清除不需要再使用的内存 - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { }// 程序即将退出调用 - (void)applicationWillTerminate:(UIApplication *)application { } AppDelegate加载顺序 1.application:didFinishLaunchingWithOptions: 2.applicationDidBecomeActive: ViewController中的加载顺序 1.loadView 2.viewDidLoad 3.viewWillAppear 4.viewWillLayoutSubviews 5.viewDidLayoutSubviews 6.viewDidAppear View中的加载顺序 1.initWithCoder如果没有storyboard就会调用initWithFrame这里两种方法视为一种 2.awakeFromNib 3.layoutSubviews 4.drawRect 一些方法的使用时机 (void)load; 应用程序启动就会调用的方法在这个方法里写的代码最先调用。 (void)initialize; 用到本类时才调用这个方法里一般设置导航控制器的主题等如果在后面的方法设置导航栏主题就太迟了 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions; 这个方法里面会创建UIWindow设置根控制器并展现比如某些应用程序要加载授权页面也是在这加也可以设置观察者监听到通知切换根控制器等。 - (void)awakeFromNib; 在使用IB的时候才会涉及到此方法的使用当.nib文件被加载的时候会发送一个awakeFromNib的消息到.nib文件中的每个对象每个对象都可以定义自己的awakeFromNib函数来响应这个消息执行一些必要的操作。在这个方法里设置view的背景等一系列普通操作。 - (void)loadView; 创建视图的层次结构在没有创建控制器的view的情况下不能直接写 self.view 因为self.view的底层是 if_view nil{ _view [self loadView] } 这么写会直接造成死循环。 如果重写这个loadView方法里面什么都不写会显示黑屏。 - (void)viewWillLayoutSubviews; 视图将要布局子视图苹果建议的设置界面布局属性的方法这个方法和viewWillAppear里系统的底层都是没有写任何代码的也就是说这里面不写super 也是可以的。 - (void)layoutSubviews; 在这个方法里一般设置子控件的frame。 - (void)drawRect:(CGRect)rect; UI控件都是画上去的在这一步就是把所有的东西画上去。drawRect方法只能在加载时调用一次如果后面还需要调用比如下载进度的圆弧需要一直刷帧就要使用setNeedsDisplay来定时多次调用本方法。 - (void)applicationDidBecomeActive:(UIApplication *)application; 这是AppDelegate的应用程序获取焦点方法真正到了这里才是所有东西全部加载完毕。 启动分析 应用启动时会播放一个启动动画。iPhone上是400msiPad上是500ms。如果应用启动过慢用户就会放弃使用甚至永远都不再回来。为了防止一个应用占用过多的系统资源开发iOS的苹果工程师门设计了一个“看门狗”的机制。在不同的场景下“看门狗”会监测应用的性能。如果超出了该场景所规定的运行间“看门狗”就会强制终结这个应用的进程。 iOS App启动时会链接并加载Framework和Static lib执行UIKit初始化然后进入应用程序回调执行Core Animation transaction等。每个Framework都会增加启动时间和占用的内存不要链接不必要的Framework必要的Framework不要标记为Optional。避免创建全局的C对象。 初始化UIKit时字体、状态栏、user defaults、Main.storyboard会被初始化。User defaults本质上是一个plist文件保存的数据是同时被反序列化的不要在user defaults里面保存图片等大数据。 对于 OC 来说应尽量减少 class,selector 和 category 这些元数据的数量。编码原则和设计模式之类的理论会鼓励大家多写精致短小的类和方法并将每部分方法独立出一个类别但这会增加启动时间。在调用的地方使用初始化器不要使用atribute((constructor)) 将方法显式标记为初始化器而是让初始化方法调用时才执行。比如使用 dispatch_once(),pthread_once() 或 std::once()。也就是在第一次使用时才初始化推迟了一部分工作耗时。 建立网络连接前需要做域名解析如果网关出现问题dns解析不正常时dns的超时时间是应用控制不了的。在程序设计时要考虑这些问题如果程序启动时有网络连接应尽快的结束启动过程网络访问通过线程解决而不阻塞主线程的运行。
http://www.dnsts.com.cn/news/111370.html

相关文章:

  • 不会做网站巴州网站建设
  • 韩国优秀网站欣赏孵化器网站建设
  • 购买网站空间自己怎样建立网站网页设计作业宽度1366768
  • 顺德网站建设公司有哪些wordpress注册发送验证码
  • 网站的切换语言都是怎么做的wordpress后台上传主题更新失败
  • 社群营销怎么做seo做什么网站赚钱
  • 用vs做网站的登录网站在线支付功能
  • 路由器设置网站苏州保洁公司开荒保洁收费标准
  • 口碑最好的购物网站平台网站方案策划书18000字
  • 维护网站英语怎么做下载类网站
  • 公司做百度网站要多少钱做苗木网站哪家好
  • 校园网二级网站的建设岳阳网站设计
  • 网站改版不换域名怎么做网站联盟是什么
  • 深圳网站开发公司有哪些seo优化培训
  • 国外最火的网站合肥网站建设5k5
  • 做网站跟推广哪家公司好看空间
  • 做网站销售电销好做吗用台式机做网站服务器
  • 聊城市住房和城乡建设局网站首页打开浏览器直接进入网站
  • php语言做购物网站打鱼网站怎么做
  • 仙居制作网站免费linux网站空间
  • 颍上做网站做彩票网站网址
  • 厦门思总建设有限公司网站深圳有哪些软件外包公司
  • 如何用网站首页做404如何推广店铺呢
  • 仿网站开发必要是什么网站
  • 目前网站开发有什么缺点网站建设需求确认表
  • 做视频自媒体要投稿几个网站wordpress支持视频播放器插件
  • 网站商城建设基本流程广州引流推广公司
  • 页面设计模板网站wordpress 5.2.2
  • dede页码的调用 网站集团形象设计公司
  • 网站建设1000字百度用户服务中心