美文网首页
性能优化

性能优化

作者: 一达 | 来源:发表于2019-08-01 09:49 被阅读0次

    性能优化

    参考文章:
    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就可能被系统杀掉。

    相关文章

      网友评论

          本文标题:性能优化

          本文链接:https://www.haomeiwen.com/subject/spgfdctx.html