尽量使用ARC
ARC不仅可以帮你避免内存泄露,还可以帮你提高性能,它能保证释放掉不再需要的对象的内存.
尽量把Views设置成为不透明
如果你有不透明的Views,你应该设置它们的opaque属性为YES。Apple的文档对于为图片设置不透明属性的描述是:
(opaque)这个属性给渲染系统提供了一个如何处理这个view的提示。如果设为YES, 渲染系统就认为这个view是完全不透明的,这使得渲染系统优化一些渲染过程和提高性能。如果设置为NO,渲染系统正常地和其它内容组成这个View。默认值是YES。
在相对比较静止的画面中,设置这个属性不会有太大影响。然而当这个view嵌在scroll view里边,或者是一个复杂动画的一部分,不设置这个属性的话会在很大程度上影响app的性能。
不要阻塞主线程
永远不要使主线程承担过多。因为UIKit在主线程上做所有工作,渲染,管理触摸反应,回应输入等都需要在它上面完成。
所以除了渲染,触摸,输入,等功能外,其他的功能尽量在子线程中进行处理,特别当处理的逻辑很大,消耗CPU较高的情况下。
不要在ImageViews中调整图片大小
如果在UIImageVIew中显示一个来自bundle的图片,你应保证图片的大小和UIImageVIew的大小相同。因为在运行中缩放图片是很耗资源的,特别是UIImageVIew嵌套在UIScrollVIew中的情况下。 如果图片是在远端服务器加载的你不能控制图片的大小,你可以在下载完成后,最好用background thread,缩放一次,然后在UIImageView中使用缩放后的图片。
选择正确的collection
学会选择对业务场合最适合的类或者对象是写出高效代码的基础,一些常见的collections的总结:
- Arrays:有序的一组值。使用index来lookup很快,使用value lookup很慢,插入/删除很慢的。
- Dictionaries:存储键值对。用键来查找比较快。
- Sets:无序的一组值。用值来查找很快,插入/删除很快。
重用大开销对象
一些objects的初始化很慢,比如NSDateFormatter和NSCalendar。然而,你又不可避免地需要使用它们,比如从JSON或者XML中解析数据。
下面的代码说明了使用一个属性来延迟加载一个date formatter. 第一次调用时它会创建一个新的实例,以后的调用则将返回已经创建的实例:
## 选择正确的数据格式
从app和网络服务间传输数据有很多方案,最常见的就是JSON和XML。你需要选择对你的app来说最合适的一个。
解析JSON会比XML更快一些,JSON也通常更小更便于传输。从iOS5起有了官方内建的JSON deserialization 就更加方便使用了,但是XML也有XML的好处,比如使用SAX 来解析XML就像解析本地文件一样,你不需像解析json一样等到整个文档下载完成才开始解析。当你处理很大的数据的时候就会极大地减低内存消耗和增加性能。
## 正确设定背景图片
在View里放背景图片就像很多其它iOS编程一样有很多方法:
1. 使用UIColor的 colorWithPatternImage来设置背景色;
2. 在view中添加一个UIImageView作为一个子View。
如果你使用全画幅的背景图,你就必须使用UIImageView因为UIColor的colorWithPatternImage是用来创建小的重复的图片作为背景的。这种情形下使用UIImageView可以节约不少的内存:
如果你用小图平铺来创建背景,你就需要用UIColor的colorWithPatternImage来做了,它会更快地渲染也不会花费很多内存:
## 选择正确实现Shadow Path的方式
如何在一个View或者一个layer上加一个shadow呢,QuartzCore框架是很多开发者的选择:
看起来很简单,对吧。
可是,坏消息是使用这个方法也有它的问题… Core Animation不得不先在后台得出你的图形并加好阴影然后才渲染,这开销是很大的。
使用shadowPath的话就避免了这个问题:
使用shadow path的话iOS就不必每次都计算如何渲染,它使用一个预先计算好的路径。但问题是自己计算path的话可能在某些View中比较困难,且每当view的frame变化的时候你都需要去update shadow path.
## 选择是否缓存图片
常见的从bundle中加载图片的方式有两种,一个是用`imageNamed`,二是用`imageWithContentsOfFile`,第一种比较常见一点。
既然有两种类似的方法来实现相同的目的,那么他们之间的差别是什么呢?
`imageNamed`的优点是当加载时会缓存图片。`imageNamed`的文档中这么说:
这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象如果它存在的话。如果缓存中没有找到相应的图片,这个方法从指定的文档中加载然后缓存并返回这个对象。
相反的,`imageWithContentsOfFile`仅加载图片。
下面的代码说明了这两种方法的用法:
那么我们应该如何选择呢?
如果你要加载一个大图片而且是一次性使用,那么就没必要缓存这个图片,用`imageWithContentsOfFile`足矣,这样不会浪费内存来缓存它。
然而,在图片反复重用的情况下`imageNamed`是一个好得多的选择。