性能优化:1.启动优化:冷启动(从零开始启动App)热启动(App已在内存,在后台存活着,再次点击图标启动App)
添环境变量打印启动时间Edit scheme->Run->Arguments添DYLD_PRINT_STATISTICS设置为1若需更详细信息_DETAILS
冷启动3个阶段:dyld runtime main(之前初始化 dyld主导将可执行文件加载到内存,加载依赖的动态库包括解析/绘制/重定位/绑定图片;runtime负责加载成objc定义的结构包括加载类/分类、属性/构造函数和C++静态分配对象构造器;之后初始化调用main UIApplicationMain willFinishLaunch())
dyld dynamic link editor动态链接器,可装载Mach-O文件(可执行文件、递归加载依赖的动态库等),装载完毕会通知runtime下一步处理
App启动时runtime所做的事情:调用map_images进行可执行文件内容的解析和处理
在load_images中调用call_load_methods,调用所有Class和Category的+load方法
进行各种objc结构的初始化(注册Objc类 、初始化类对象等等)
调用C++静态初始化器和__attribute__((constructor))修饰的函数
到此为止,可执行文件和动态库中所有的符号(Class,Protocol,Selector,IMP,…)都已经按格式成功加载到内存中,被runtime 所管理
知道启动3阶段原理后,从3方面做启动优化:
dyld
•减少动态库、合并一些动态库(定期清理不必要的动态库)
•减少Objc类、分类的数量、减少Selector数量(定期清理不必要的类、分类)
•减少C++虚函数数量
•Swift尽量使用struct
●runtime
•用+initialize方法和dispatch_once取代所有的__attribute__((constructor))、C++静态构造器、ObjC的+load
●main
•在不影响用户体验的前提下,尽可能将一些操作延迟,不要全部都放在finishLaunching方法中
•按需加载
缩短启动时长尤其首次启动 尽可能多做异步任务比如加载或解析远端/数据库数据 避免庞大xib或storyboard因为它们是在主线程加载的
瘦身请求依赖、UDP启动请求先缓存、队列串行化处理启动响应
2.内存优化 App瘦身
●安装包(IPA)主要由可执行文件、资源组成
●资源(图片、音频、视频等)
●采取无损压缩
●去除没有用到的资源: https://github.com/tinymind/LSUnusedResources
●可执行文件瘦身
●编译器优化
•Strip Linked Product、Make Strings Read-Only、Symbols Hidden by Default设置为YES
•去掉异常支持,Enable C++ Exceptions、Enable Objective-C Exceptions设置为NO, Other C Flags添加-fno-exceptions
●利用AppCode(https://www.jetbrains.com/objc/)检测未使用的代码:菜单栏 -> Code -> Inspect Code
●编写LLVM插件检测出重复代码、未被调用的代码
ARC下 依然是延时释放、依赖于NSAutoreleasePool如释放block中autoreleased 对象,只是在编译阶段帮你插入必要retain\release\autorelease代码。正常情况创建的变量会在超出作用域时被释放,但当写的函数很长,函数运行过程中有很多中间变量 或创建很多临时对象而占据大量内存就 在@autoreleasepool里创建对象,在结束时执行一次release,相当于一层作用域,避免的内存峰值
从bundle加载图片 用imageNamed 或imageWithContentsOfFile
避免日期格式转换 NSDateFormatter很耗时,若能控制所处理日期尽量用Unix时间戳 比用C解析日期字符串还快即-(NSDate*)dateFromUnixTimestamp:(NSTimeInterval)timestamp{ return [NSDate dateWithTimeIntervalSince1970:timestamp];} 注意:webAPI以微秒返回时间戳,方便js用故用dateFromUnixTimestamp:前除以1000
如何对代码性能优化:Product->Analyze\Profile性能分析工具检测;TimeProfiler程序运行后能获取到整个应用运行耗时分布和百分比,用真机分析因为模拟器在Mac上,cpu比iOS设备快;
UIImage加载图性能问题
imageNamed初始化 默认加载后缓存到内存 先缓存中找并返回图片 无则指定地方加载
imageWithContentsOfFile加载不缓存 大图仅用一次
viewWillAppear只做view的背景色、字体等显示属性设置,不要复杂费时操作否则会明显卡顿或延迟
view设置opaque为YES系统会以最优方式渲染
避免过大xib尽可能view层次结构分散到单独xib nib若引用了声音或图片nib加载代码会把图片和声音文件写进内存
不要阻塞主线程 避免如存储或网络等读写外部资源的I/O操作 因为渲染、管理触摸反应、回应输入等UIKit所有工作都在主线程
若从bundle中显示图片 图片大小和UIIMageView大小相同 运行中缩放图片很耗资源
内存泄漏:忘记Release操作、循环引用导致无法释放 MemoryLeaks\Allocations\Analyse\Debug Memory Graph比较麻烦需要不断调试运行,MLeaksFinder腾讯阅读团队出品效果较好
高性能画圆角
视图和圆角大些对帧率无影响 数量才是
label.layer.cornerRadius=5 .maskToBounds= true 次做法不可取
只用cornerRadius
若必须用maskToBounds可考虑圆角试图数量,(一页只几个不用)多才需要优化。UIImageView的圆角直接截取UI图,其他用CoreGraphics绘制
App电量优化:定位、网络、图像、CPU处理
尽可能降低CPU、GPU功耗,少用定时器
优化I/O操作:不频繁写小数据而是攒到一定量再写入、读写大数据用Dispatch_IO、数量较大用数据库
网络
定位
硬件检测:移动、摇晃、倾斜等由加速计、陀螺仪、磁力计等硬件检测,在不需要时及时关闭
3.界面优化
4.架构优化
图片资源瘦身
1.借助工具LSUnusedResources进行未使用的图片和图片代码的删除
2.和UI沟通在合理范围内压缩资源图片
3.不常用的大图可下载到app而非打包到ipa
代码瘦身
App打包成ipa时,代码会被打包成一个个.o文件,这些.o文件组成了MachO,而系统在编译MachO文件时会生成一个附带文件LinkMap
1.LinkMap由ObjectFile、Section、Symbol组成,描述了工程所有代码的信息。
LinkMap的获取a.Project-BuildSettings-Linking搜索write Link Map File设置为YES
b.path to Link Map File设置好地址 c.运行项目将在地址位置生成.txt
-
借助工具LinkMap解析工具,我们可以分析每个类占用的大小
-
针对性的进行代码体积优化,比如三方库占用空间巨量,有没其他的替代方案。以体积比重取舍两个相同功能的库
-
通过MachOView这个软件我们可以更加直观看到MachO的组成。如果你的MachOView运行的时候出现崩溃请按照这篇文章进行修改
。
__objc_selrefs:记录了几乎所有被调用的方法
__objc_classrefs和__objc_superrefs:记录了几乎所有使用的类
__objc_classlist:工程里所有的类的地址
AppCode
如果你的工程不够巨大,借助AppCode这个工具的静态分析也可以查找到未使用的代码。方法极为简单打开AppCode->选择Code->点击Inspect Code—等待静态分析
https://www.jianshu.com/p/cb6d954bd9a6 -
借助工具LinkMap解析工具,我们可以分析每个类占用的大小
-
针对性的进行代码体积优化,比如三方库占用空间巨量,有没其他的替代方案。以体积比重取舍两个相同功能的库
-
通过MachOView这个软件我们可以更加直观看到MachO的组成。如果你的MachOView运行的时候出现崩溃请按照这篇文章进行修改
。
__objc_selrefs:记录了几乎所有被调用的方法
__objc_classrefs和__objc_superrefs:记录了几乎所有使用的类
__objc_classlist:工程里所有的类的地址
AppCode
如果你的工程不够巨大,借助AppCode这个工具的静态分析也可以查找到未使用的代码。方法极为简单打开AppCode->选择Code->点击Inspect Code—等待静态分析
https://www.jianshu.com/p/cb6d954bd9a6