性能优化

性能优化

参考文章:
https://www.jianshu.com/p/c51106cbea05

一、tableView的优化

1、使用tableViewCell复用,利用缓冲池。 每次刷新显示都会去创建新的Cell,非常耗费性能。
解决方案:首先创建一个静态变量reuseID(代理方法返回Cell会调用很多次,防止重复创建,static保证只会被创建一次,提高性能),然后,从缓存池中取相应identifier的Cell并更新数据,如果没有,才开始alloc新的Cell,并用identifier标识Cell。每个Cell都会注册一个identifier(重用标识符)放入缓存池,当需要调用的时候就直接从缓存池里找对应的id,当不需要时就放入缓存池等待调用。(移出屏幕的Cell才会放入缓存池中,并不会被release)所以在数据源方法中做出如下优化:

2、heightForRow
如果是动态计算的,将高度存入模型中。避免每次计算

3、异步绘制
如果需要对图片进行圆角处理等,可以通过CGContextRef方法性能更高

4、避免大量的图片缩放、颜色渐变尽量显示“大小刚好合适的图片资源”

5、避免同步的从网络、文件获取数据,Cell内实现的内容来自web,使用异步加载,缓存请求结果

6、渲染
a.减少subviews的个数和层级
子控件的层级越深,渲染到屏幕上所需要的计算量就越大;如多用drawRect绘制元素,替代用view显示
b.少用subviews的透明图层
对于不透明的View,设置opaque为YES,这样在绘制该View时,就不需要考虑被View覆盖的其他内容(尽量设置Cell的view为opaque,避免GPU对Cell下面的内容也进行绘制)
c.避免CALayer特效(shadowPath)
给Cell中View加阴影会引起性能问题,如下面代码会导致滚动时有明显的卡顿:

二、程序启动优化

1、开启时间分析功能
在Xcode的菜单中选择Project→Scheme→Edit Scheme...,然后找到Run → Environment Variables → +,添加name为DYLD_PRINT_STATISTICSvalue为1的环境变量。

2、结论分析
Total pre-main time: 94.33 milliseconds (100.0%)
dylib loading time: 61.87 milliseconds (65.5%)
rebase/binding time: 3.09 milliseconds (3.2%)
ObjC setup time: 10.78 milliseconds (11.4%)
initializer time: 18.50 milliseconds (19.6%)
slowest intializers :
libSystem.B.dylib : 3.59 milliseconds (3.8%)
libBacktraceRecording.dylib : 3.65 milliseconds (3.8%)
MyTest : 7.09 milliseconds (7.5%)

main()函数之前总共使用了94.33ms
在94.33ms中,加载动态库用了61.87ms,指针重定位使用了3.09ms,ObjC类初始化使用了10.78ms,各种初始化使用了18.50ms。
在初始化耗费的18.50ms中,用时最多的三个初始化是libSystem.B.dylib、libBacktraceRecording.dylib以及MyTest。

动态库、ObjC 和ObjC的+load方法越多启动越慢

三、其他优化建议

1.不要阻塞主线程

2.尽可能设置 View 为不透明

3.避免臃肿的 XIB 文件

4.启用 GZIP 数据压缩

5.View 的复用、懒加载

6、缓存
服务器的响应信息(response)、图片、计算值。比如:UITableView 的 row heights。

7.处理内存警告
在 AppDelegate 中实现 - [AppDelegate applicationDidReceiveMemoryWarning:] 代理方法。
在 UIViewController 中重载 didReceiveMemoryWarning 方法。
监听 UIApplicationDidReceiveMemoryWarningNotification 通知。

8.复用高开销的对象

9.减少应用启动时间
快速启动应用对于用户来说可以留下很好的印象。尤其是第一次使用时。
保证应用快速启动的指导原则:
尽量将启动过程中的处理分拆成各个异步处理流,比如:网络请求、数据库访问、数据解析等等。
避免臃肿的 XIB 文件,因为它们会在你的主线程中进行加载。重申:Storyboard 没这个问题,放心使用。
注意:在测试程序启动性能的时候,最好用与 Xcode 断开连接的设备进行测试。因为 watchdog 在使用 Xcode 进行调试的时候是不会启动的。

10.使用 Autorelease Pool (内存释放池)

11.imageNamed 和 imageWithContentsOfFile
imageNamed:创建的对象会缓存到系统内存中,不会立即释放到内存。好处是再次加载使用这种方式会减少读取操作,加快程序运行。缺点:加载过多图片会占用大量内存空间。
mageWithContentsOfFile创建的对象不会缓存到系统内存中。好处是不产生缓存。缺点:对于经常使用的小图片,会频繁读取。

 加载图片:
  1->如果在项目中的Assets.xcassets(蓝色文件夹)
    a.不可以NSBundle获得资源路径,然后imageWithContentsOfFile加载
    b.可以imageNamed加载

  2->如果在项目中真实文件夹(蓝色文件夹,除Assets.xcassets):
    a.可以NSBundle获得资源路径,然后imageWithContentsOfFile加载。注意要带文件夹路径,例如
    [[NSBundle mainBundle]pathForResource:@"test.jpg" ofType:nil inDirectory:@"image"]
    b.不可以imageNamed加载

  3->如果在项目中虚拟文件夹(黄色文件夹)
    a.可以NSBundle获得资源路径,然后imageWithContentsOfFile加载
    b.可以imageNamed加载

12、延迟加载图片
有时候在边滚动边设置图片的时候可能会有一定的影响,因此可以在滚动的时候imageview不执行setimage的操作,滚动停止的时候才加载图片,由于滚动的时候NSRunloop是处于UITrackingRunLoopMode模式下,可以采用如下的方式,将设置图片放到NSDefaultRunLoopMode模式下才进行:
UIImage *downloadedImage = ...;
[self.avatarImageView performSelector:@selector(setImage:)
withObject:downloadedImage
afterDelay:0
inModes:@[NSDefaultRunLoopMode]];

13.减少离屏渲染(设置圆角和阴影的时候可以选用绘制的方法)

14.优化 UITableView
通过正确的设置 reuseIdentifier 来重用 Cell。
尽量减少不必要的透明 View。
尽量避免渐变效果、图片拉伸和离屏渲染。
当不同的行的高度不一样时,尽量缓存它们的高度值。
如果 Cell 展示的内容来自网络,确保用异步加载的方式来获取数据,并且缓存服务器的 response。
使用 shadowPath 来设置阴影效果。
尽量减少 subview 的数量,对于 subview 较多并且样式多变的 Cell,可以考虑用异步绘制或重写 drawRect。
尽量优化 - [UITableView tableView:cellForRowAtIndexPath:] 方法中的处理逻辑,如果确实要做一些处理,可以考虑做一次,缓存结果。
选择合适的数据结构来承载数据,不同的数据结构对不同操作的开销是存在差异的。
对于 rowHeight、sectionFooterHeight、sectionHeaderHeight 尽量使用常量。

15.选择合适的数据存储方式
在 iOS 中可以用来进行数据持有化的方案包括:
NSUserDefaults。只适合用来存小数据。
XML、JSON、Plist 等文件。JSON 和 XML 文件的差异在「选择正确的数据格式」已经说过了。
使用 NSCoding 来存档。NSCoding 同样是对文件进行读写,所以它也会面临必须加载整个文件才能继续的问题。
使用 SQLite 数据库。可以配合 FMDB 使用。数据的相对文件来说还是好处很多的,比如可以按需取数据、不用暴力查找等等。
使用 CoreData。也是数据库技术,跟 SQLite 的性能差异比较小。但是 CoreData 是一个对象图谱模型,显得更面向对象;SQLite 就是常规的 DBMS。

16.减少应用启动时间
快速启动应用对于用户来说可以留下很好的印象。尤其是第一次使用时。
保证应用快速启动的指导原则:
尽量将启动过程中的处理分拆成各个异步处理流,比如:网络请求、数据库访问、数据解析等等。
避免臃肿的 XIB 文件,因为它们会在你的主线程中进行加载。重申:Storyboard 没这个问题,放心使用。
注意:在测试程序启动性能的时候,最好用与 Xcode 断开连接的设备进行测试。因为 watchdog 在使用 Xcode 进行调试的时候是不会启动的。

17.使用 Autorelease Pool (内存释放池)

18.imageNamed 和 imageWithContentsOfFile

19.对于圆角可以使用一张中间圆形透明的图覆盖在上面,虽然这会引入blending操作,但是大部分情况下性能会比离屏渲染好。

20.利用枚举遍历数组,效率比for循环高

21.加载图片时用imageWithContentsOfFiles 这样不会讲图片缓存到内存中,同时要避免图片缩放,因为这是很消耗性能

22.处理内存警告
UIViewController的默认行为是移除一些不可见的view,这样对内存警报的处理是很必要的,若不重视,你的app就可能被系统杀掉。

你可能感兴趣的:(性能优化)