发现代码中有一个嵌套的`dispatch_async`吗?这是因为任何UIKit相关的代码需要在主线程上进行。

  如果你对 NSOperation 或者GCD 的细节感兴趣的话,看看Ray Wenderlich的 Multithreading and Grand Central Dispatch on iOS for Beginners, 还有 Soheil Azarpour 的 How To Use NSOperations and NSOperationQueues 教程。

  6. 在Image Views中调整图片大小

  如果要在`UIImageView`中显示一个来自bundle的图片,你应保证图片的大小和UIImageView的大小相同。在运行中缩放图片是很耗费资源的,特别是`UIImageView`嵌套在`UIScrollView`中的情况下。

  如果图片是从远端服务加载的你不能控制图片大小,比如在下载前调整到合适大小的话,你可以在下载完成后,好是用background thread,缩放一次,然后在UIImageView中使用缩放后的图片。

  7. 选择正确的Collection

  学会选择对业务场景合适的类或者对象是写出能效高的代码的基础。当处理collections时这句话尤其正确。

  Apple有一个 Collections Programming Topics 的文档详尽介绍了可用的classes间的差别和你该在哪些场景中使用它们。这对于任何使用collections的人来说是一个必读的文档。

  呵呵,我知道你因为太长没看…这是一些常见collection的总结:

  Arrays: 有序的一组值。使用index来lookup很快,使用value lookup很慢, 插入/删除很慢。

  Dictionaries: 存储键值对。 用键来查找比较快。

  Sets: 无序的一组值。用值来查找很快,插入/删除很快。

  8. 打开gzip压缩

  大量app依赖于远端资源和第三方API,你可能会开发一个需要从远端下载XML, JSON, HTML或者其它格式的app。

  问题是我们的目标是移动设备,因此你不能指望网络状况有多好。一个用户现在还在edge网络,下一分钟可能切换到了3G。不论什么场景,你肯定不想让你的用户等太长时间。

  减小文档的一个方式是在服务端和你的app中打开gzip。这对于文字这种能有更高压缩率的数据来说会有更显著的效用。

  好消息是,iOS已经在NSURLConnection中默认支持了gzip压缩,当然AFNetworking这些基于它的框架亦然。像Google App Engine这些云服务提供者也已经支持了压缩输出。

  如果你不知道如何利用Apache或者IIS(服务器)来打开gzip,可以读下这篇文章。

  中级性能提升

  你确信你已经掌握了前述那些基础级的优化方案了吗?但实际情况是,有时一些解决方案并不像那些一样明显,它们往往严重依赖于你如何架构和书写你的app。下面的这些建议是针对这些场景的。

  9. 重用和延迟加载(lazy load) Views

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

  这里我们用到的技巧是模仿`UITableView`和`UICollectionView`的操作: 不要一次创建所有的subview,而是当需要时才创建,当它们完成了使命,把他们放进一个可重用的队列中。

  这样的话你只需要在滚动发生时创建你的views,避免了不划算的内存分配。

  创建views的能效问题也适用于你app的其它方面。想象一下一个用户点击一个按钮的时候需要呈现一个view的场景。有两种实现方法:

  1. 创建并隐藏这个view当这个screen加载的时候,当需要时显示它;

  2. 当需要时才创建并展示。

  每个方案都有其优缺点。

  用第一种方案的话因为你需要一开始创建一个view并保持它直到不再使用,这会更加消耗内存。然而这也会使你的app操作更敏感因为当用户点击按钮的时候它只需要改变一下这个view的可见性。

  第二种方案则相反-消耗更少内存,但是会在点击按钮的时候比第一种稍显卡顿。

  10. Cache, Cache, 还是Cache!

  一个极好的原则是,缓存所需要的,也是那些不大可能改变但是需要经常读取的东西。

  我们能缓存些什么呢?一些选项是,远端服务器的响应,图片,甚至计算结果,比如UITableView的行高。

  NSURLConnection默认会缓存资源在内存或者存储中根据它所加载的HTTP Headers。你甚至可以手动创建一个NSURLRequest然后使它只加载缓存的值。

  下面是一个可用的代码段,你可以可以用它去为一个基本不会改变的图片创建一个NSURLRequest并缓存它:
 
+ (NSMutableURLRequest *)imageRequestWithURL:(NSURL *)url {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
 
    request.cachePolicy = NSURLRequestReturnCacheDataElseLoad; // this will make sure the request always returns the cached image
    request.HTTPShouldHandleCookies = NO;
    request.HTTPShouldUsePipelining = YES;
    [request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
 
    return request;
}