iOS性能优化的初步体验

解决方案

1. 正确使用reuseIdentifier
2. 不要阻塞主线程
3. 重用和延迟加载Views
4. 缓存不容易修改且利用率高的资源
5. 重用开销大的对象
6. 选择正确的方式加载本地图片
7. 使用WKWebView替代UIWebView
8. UITableView 性能优化
9. 处理内存警告
10. 用户体验提高

1. 正确使用reuseIdentifierweb

  1. UITableView中UITableViewCell重用
    //1. 注册(Cell 为纯代码)
    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell_Reuse"];
    //2. 注册(Cell 包含Nib 文件)
    [tableView registerNib:[UINib nibWithNibName:@"TalkCell" bundle:nil] forCellReuseIdentifier:@"TalkCell_Reuse"];
    // 根据reuseIdentifier获取
    [tableView dequeueReusableCellWithIdentifier:@"TalkCell_Reuse" forIndexPath:indexPath];
  2. UITableView中UITableViewHeaderFooterViews的重用,
    UITableViewHeaderFooterViews为Section的Header或者Footer。
    // 注册
    [tableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"UITableViewHeaderFooterView_Reuse"];
    // 根据reuseIdentifier获取
    [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"UITableViewHeaderFooterView_Reuse"];
  3. UICollectionView中UICollectionViewCell重用,同UITableViewCell重用相似
  4. UICollectionView中Supplementary Views重用(追加视图)相似于UITableView中Section的Header或者Footer.

2. 不要阻塞主线程数据库

主线程负责UI更新,渲染,用户交互处理等事件,为了避免阻塞主线程,除此以外的一些复杂和耗时的操做必须放在子线程中去执行。常见的如获取网络资源。缓存

//阻塞主线程
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.baiu.com"]];
//解决方案
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.baiu.com"]];
    });

3. 重用和延迟加载(lazy load)Views性能优化

更多的view意味着更多的渲染,也就是更多的CPU和内存消耗,对于那种嵌套了不少view在UIScrollView里边的app更是如此。服务器

  1. 常见的广告图浏览,或者图片放大查看器可仿照UITableView或者UICollectionView进行重用,只建立有效数量的View,减小CPU和内存消耗。
  2. 不要一次建立全部的subview,而是当须要时才建立(lazy load/懒加载)。如一个筛选器(当点击筛选按钮才会弹出筛选界面)在效率和内存方面都获得提高。

4. 缓存不容易修改且利用率高的资源微信

一个极好的原则就是,缓存所须要的,也就是那些不大可能改变可是须要常常读取的东西。
咱们能缓存些什么呢?一些选项是,远端服务器的响应,图片,甚至计算结果。网络

  1. 网络图片的缓存,如SDWebImage
  2. UITableView Cell 的行高,或者Header/Footer行高等
  3. 数据处理结果。

5. 重用开销大的对象数据结构

一些对象的初始化很慢,好比NSDateFormatter和NSCalendar。然而,你又不可避免地须要使用它们。那么能够把它做为一个属性或者是单例来使用。但做为单例会一直占用内存。app

6. 选择正确的方式加载本地图片框架

  1. 加载常常使用的小图片
    [UIImage imageNamed:@"hello.png"];
    特色:这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象若是它存在的话。若是缓存中没有找到相应的图片,这个方法从指定的文档中加载而后缓存并返回这个对象。
    优势:由于有缓存,第二次加载同一张图片,则速度更快。
    缺点:有缓存,更多的内存消耗。
  2. 不常常使用,或者大图片:
    //图片路径
     NSString *path = [[NSBundle mainBundle]pathForAuxiliaryExecutable:@"hello.png"];
     //根据路径加载图片
     [UIImage imageWithContentsOfFile:path];
    特色:每次都是找到对应路径的图片以后再加载图片,无缓存。

7. 使用WKWebView替代UIWebView

iOS8之后,苹果推出了新框架Wekkit,提供了替换UIWebView的组件WKWebView。各类UIWebView的问题没有了,速度更快了,占用内存少了,一句话,WKWebView是App内部加载网页的最佳选择!

8. UITableView 性能优化

  • 正确使用reuseIdentifier来重用cells及Section 的Header 和Footer
  • 若是行高是变化的,则缓存行高,如cell,Section的Header和Footer的行高。
  • 若是行高是固定的,使用使用tableView,rowHeight,
    sectionFooterHeight 和 sectionHeaderHeight来设定固定的高,不用实现代理方法。
  • 若是cell内现实的内容来自web,使用异步加载,缓存请求结果,如图片等
  • Cell数据资源的缓存,避免重复处理数据。如富文本的多样化显示(NSString->NSAttributeString),时间的多样化现实(2016-01-08 20:40:40 -> 9个月前)

9. 处理内存警告

一旦系统内存太低,iOS会通知全部运行中app。在官方文档中是这样记述:
若是你的app收到了内存警告,它就须要尽量释放更多的内存。最佳方式是移除对缓存,以及一切可再生资源.
幸运的是,UIKit提供了几种收集低内存警告的方法:

  • 在app delegate中使用applicationDidReceiveMemoryWarning: 的方法
  • 在你的自定义UIViewController的子类(subclass)中覆盖
    didReceiveMemoryWarning
  • 注册并接收 UIApplicationDidReceiveMemoryWarningNotification 的通知
    一旦收到这类通知,你就须要释听任何没必要要的内存使用。
    例如,UIViewController的默认行为是移除一些不可见的view, 它的一些子类则能够补充这个方法,删掉一些额外的数据结构。一个有图片缓存的app能够移除不在屏幕上显示的图片。
    这样对内存警报的处理是很必要的,若不重视,你的app就可能被系统杀掉。
    必定要在开发中用模拟器中的模拟内存警告。

10. 用户体验提高

本地缓存一些用户常常浏览的数据,实现离线浏览功能,如微信的朋友圈,微博的首页等。

  • 使用NSUerDefaults
  • Plist文件
  • 使用NSCoding存档
  • 使用相似SQLite的本地SQL数据库
  • 使用 Core Data

NSUserDefaults只适用于小数据,好比一些简单的布尔型的设置选项。

Plist文件只支持一些简单的系统类,如NSDictionary,NSArray,NSString等。其余类就不能用此方法。

NSCoding它须要读写文件,当储存大块数据或者要支持查询部分数据,它就没有任何优点了。

当存储大块数据时,以上的方法都不适用. 在这种应用场景下,使用SQLite 或者 Core Data比较好。使用这些技术你用特定的查询语句就能只加载你须要的对象。 SQLite是iOS内嵌的数据库,使用C语言的,用SQL语句进行数据操做。 CoreData基于SQLite封装,OC语言,底层存储数据的依然是SQLite。