前言
自己在这家公司曾经三年多了,这款三年多我始终在做的 APP 也烂熟于心,APP 也 0 到 1 到目前的 500 万的用户量;对于 APP 的性能来说也是比拟全面的,用到的技术知识点也比拟多吧,APP 的优化也是始终在做的事件,而且 APP 性能的优化也不是久而久之的事件,在此离别之际,我将具体阐明解说一下我在三年里对 APP 性能优化方面做过的一些事,大家仁者见仁智者见智,也欢送大家进群提供贵重的意见和倡议!
根底优化
应用 ARC,当初的 iOS 开发大家用的都是 ARC,简直没有人再去应用 MRC 了,应用 ARC 的益处就是不必再时时刻刻留神要开释创立的对象了;防止应用 xib 或者 storyboard。
这里说一下 xib 和 sb 的毛病吧,如下:
1. 占用 API 包比拟大;
2. 导致 APP 启动工夫比拟耗时,因为在 APP 启动 main()以前须要加载他们;
3. 加载速度比较慢;
4. 前期的版本更新迭代保护工夫老本比拟高;
5. 多人开发容易引起抵触。
列表图片优化
列表不管在哪一个 APP 中是应用最为宽泛的一款控件了,在我的 APP 中也不例外,咱们的 APP 只有性能列表相似于微信的朋友圈,图片有 0~9 张的模式还能够是视频文件;
先说一说图片吧,如果一个列表都是 9 张图片,列表在加载和滑动的时候会耗用过多的内存;我在这里是把图片这一块独自抽出来做一个图片资源的封装,而后依据创立的图片容器(UIImageView)的大小加载缩略图,咱们公司的 APP 存储用的是七牛云存储,所以在获取图片资源的时候,只须要设置对应的字段就能够拿到缩略图了,点击的查看大图的时候才查看原图;
再说说视频,视频的解决逻辑和图片差不多,这里在 CELL 上咱们应用一个 UIImageView 来代替视频播放器,能够去出视频的第一帧作为封面,点击图片的时候才调用咱们封装好的视频播放组件。
复用机制
说道复用,咱们可能罕用的有 CELL 的复用,其实咱们也能够本人写咱们的服用,就比方上图中的列表,咱们个别采纳的思路就是在主控制器上增加一个 UIScrollView, 再依据有多少个小标题类型创立多少个子控制器,接着把子控制器增加到主控制器的 childViewControllers 中,最初把子控制器的视图增加到 UIScrollView 上,有没有更节俭内存空间的做法呢???
当然有的,咱们能够只创立 5 个控制器而后丢到咱们的可重用数组中,依据每次滑动去加载不同的缓存数据;
还比方我在直播间创立刷礼物的视图动画的时候,因为最多只能显示三条,那么我只会创立三个视图,当有大于三条的礼物信息过去的时候也只会创立三个视图,而后丢进我的可重用数组外面,每个视图动画实现当前才从新复制 Model,如下图左下角的礼物动画最多三个,起码没有:
就如下面所说,在我的项目中咱们能够在很多中央创立属于咱们本人的重用机制!
离屏渲染
在开发中,咱们罕用有圆角解决、暗影、遮罩等等;先说说圆角优化吧,咱们个别设置圆角的形式如下:
view.layer.cornerRadius = 10;
view.layer.masksToBounds = YES;
这样解决的渲染机制是 GPU 在以后屏幕缓冲区外新开拓一个渲染缓冲区进行工作,也就是离屏渲染,这会给咱们带来额定的性能损耗,如果这样的圆角操作达到肯定数量,会触发缓冲区的频繁合并和上下文的的频繁切换,性能的代价会宏观地表当初用户体验上——掉帧。
优化计划:
a. 能够做一个通明的 png 图片盖在下面;
b. 应用贝塞尔曲线 UIBezierPath 和 Core Graphics 框架画出一个圆角;
c. 应用 CAShapeLayer 和 UIBezierPath 设置圆角;
d. 也能够将图片的解决放在服务端(比方:七牛云贮存就能够设置图片的圆角);
e. 尽量把 view 设置成不通明的。
阐明:离屏渲染还能够做很多货色,具体的能够自行查找!
懒加载
这里的懒加载次要说的是懒加载思维,能够懒加载的类型有很多,当然益处有很多,最次要的是能够节俭内存资源;
重大开销对象
咱们在 APP 应用过程中会用到很多重大开销对象(比方 NSDateFormatter 和 NSCalendar),如咱们在列表须要计算用户年龄的时候会常常用到 NSDateFormatter,还有一些工夫的格式化输入,或者在网络申请的时候须要传一些工夫戳,所以咱们能够把 NSDateFormatter 放在单利外面,这样就不必常常创立了,其余的也是同样的情理。
还有就是,像年龄生日什么的最好不要由前端 APP 来计算,最好放在服务器上,由服务端计算好而后再传给咱们。
内存正告
如果程序在运行过程中产生了内存正告(didReceiveMemoryWarning),咱们须要疾速应急解决一下,不要用不了多久 APP 就会被杀死掉,所在在收到内存正告次要思路就是想着去清理栈上的货色,当前咱们能够做以下几点:
a. 清理不须要的曾经创立的对象,不论是试图还是工具类;
b. 开释单利外面不须要的对象,比方上文进步过得重大开销对象;
c. 如果有正在下载的工作,勾销或者暂停全副工作;
d. 如果应用了 SDWebImage,能够清理一下缓存 clearMemory;
主线程晦涩
不要阻塞主线程,要保障主线程的流程性;咱们不要把一些重大开销对象放到主线程外面,咱们能够创立子线程去解决这些事件;比方多个网络申请完结一起刷新 UI、多个动画成果、数据的读写操作等等;
数据缓存
做缓存这个事件,一方面减小内存的小号,还有很重要的一方面就是优化用户体验;能够做缓存的货色很多,咱们能够对数据接口进行缓存,还能够对 WebView 进行缓存,还有图片缓存、高度缓存等等;
在这里不得不说一下,数据存储了;咱们在做缓存的时候抉择正确适合的存储形式也很难重要,当然大家也能够依据我的项目的理论需要来抉择存储,咱们公司的 APP 本地存储我抉择的是 SQLite,治理类是我基于 FMDB 的又一次封装.
网络 API 优化
这个优化不单单需是前端小伙伴的事,还须要后端开发人员的配合,防止一些不必要数据的返回,更要防止在 APP 端解决或者计算太多货色,比方年龄、星座的计算;即便后端的小伙伴把一些不必要的数据返回了,咱们在创立数据模型 Model 的时候能够抉择不去接管!
PS:这里我须要吐槽一下,以前公司有个 java 后端,返回的数据全副是一个表的实体类,管你有用没用,间接一股脑的全给你,本人去计算和本人去查找,那真叫一个心累啊,所以一个优良的 API 开发工程师也是一个十分重要的起因!
主动开释池
主动开释池(autoreleasepool)在 MRC 的时代真是用的十分多,然而当初的我的项目都是 ARC,主动开释池用的也就比拟少了,因为有零碎帮咱们监管,然而如果咱们一个页面创立了太多的类或者对象,如果等页面销毁的时候由零碎对立开释难免会呈现一个峰值影响整体性能,这时候咱们就能够思考应用 autoreleasepool 了,防止峰值的呈现!?
还比方咱们在遍历一些大数组或者字典的时候,能够应用主动开释池来升高内存峰值,比方:
NSArray *bigArray = @[] // 这是一个很大很大的数组
NSMutableArray *newArray = [[NSMutableArray alloc] init];
for (NSStirng *item in bigArray) {
@autoreleasepool {
ZFJModel *model = [[ZFJModel alloc] init];
model.item = item;
[newArray addObject: model];
}
}
APP 启动优化
在 AppDelegate 外面咱们会写一些很多货色,你写的货色越多越影响 APP 的冷启动工夫就会越长,因而咱们须要对 AppDelegate 进行减负,具体如何减负大家能够依据各自我的项目的理论状况,第一能够删除一些不是必须的货色;第二能够把一些货色写在别的中央(如 RootViewController),我在 APP 的 RootViewController 写的货色比方 IM 聊天的配置初始化登录,一些未解决的工作,还有一些版本的保持和缓存的清理等等!
Instruments
Instruments 是什么我这里就不作过多的介绍了,这里我次要说我用 Instruments 干什么;我平时用 Instruments 次要干两件事,一件事是查看内存透露,还有一件事是查看耗时函数;对于内存透露咱们对应批改补漏就行了,对于耗时函数要么就换一种写法,要么就创立一个子线程来解决!
? 这里要说一个我的习惯,我的所有的控制器都继承于 BaseViewController,而后我再 BaseViewController 外面写了以下的一部分代码:
- (void)dealloc{
NSLog(@”=== %@ dealloced! ===”, NSStringFromClass([self class]));
}
如果我的页面销毁不走 dealloc 的打印,那么页面必定有没有被开释的对象,要么是产生循环援用了,要么是须要手动开释,具体打印以下对象的援用计数!
本文自己首发 www.zfjobslib.com。【iOS 代码混同工具】版本:ZFJObsLib 1.7.2