初级
使用 ARC 管理内存
合理使用 reuseIdentifier
尽量不要 View 设置为透明
避免过于庞大的 XIB
不要阻塞主线程
实例
在 ImageViews 中调整图片大小. 如果要在 UIImageView 中显示一个来自 bundle 的图片, 你应保证图片的大小和 UIImageView 的大小相同. 在运行中缩放图谱按是很耗费资源的, 特别是 UIImageView 嵌套在 UIScrollView 中的情况. 如果图片是从远端服务器加载的你不能控制图片的大小, 比如在下载器前调整到合适大小的话, 你可以再狭窄完成后, 最好是用 background thread, 缩放一次, 然后在 UIImageView中是用缩放后的图片
选择正确的Collection
Array: 有序的一组值. 使用 index 来 lookup 很快, 使用 value lookup 很慢, 插入/删除很慢
Dictionaries: 储存键值对, 用 key 来查找会很快
Sets: 无序的一组值. 用值来查找会快, 插入/删除很快.
打开 gzip 压缩. app 可能大连依赖于服务器资源, 问题是我们的目标是移动设备, 因此你就不能指望网络状况有多好. 减小文档的一个方式就是在服务端和你的 app 中打开 gzip. 这对于文字种种能有更高压缩率的数据来说会有更显著的效果. iOS 已经在 NSURLConnection 中默认支持了 gzip 压缩, 当然 AFNetworking 这些基于它的框架也是.
中级
重用和延迟加载(lazy load) Views
更多的View意味着更多的渲染, 也就是更多的 CPU的内存消耗, 对于那种嵌套了很多View 在UIScrollView 你变的 app 更是如此.
这里我们用到的技巧就是模仿 UITableView 和 UICollectionView 的操作: 不要一次创建所有的 subview, 二十当需要的时候才创建, 当他们完成使命, 就把他们放进一个可从用的队列中. 这样的话你就只需要在滚动发生的时候创建你的 views, 避免不划算的内存分配.
cache
一个极好的原则就是, 缓存所需要的, 也就是那些不大可能改变你当时需要经常读取的东西.
可以缓存的东西, 远端服务器的响应, 图片, 计算记过, UITableView 的行高.
NSCache 和 NSDictionary 类似, 不同的是系统回收内存的时候他会自动删掉它的内容.
权衡渲染方法. 性能还是 bundle保持合适的大小.
处理内存警告. 移除缓存, 图片objc和其他一些可以重新创建的 object 和 strong references.
重用大开销对象
一些 Object 的初始化很慢, 比如 NSDateFormatter 和 NSCalendar. 然而, 你又不可避免的需要使用它们, 比如从 JSON 或者 XML 中解析数据. 想要避免使用这个对象的瓶颈, 你就需要重用它们, 可以通过添加属性到你的 Calss 里或者创建今天变量实现.
避免反复处理数据. 在服务器端和客户端使用相同的数据结构很重要.
选择正确的数据格式. 解析JSON 会比 XML 更快一些, JSON 也通常更小更便于传输. 从iOS5起有了官方内奸的 JSON deserialization 就更加方便使用了. 但是 XML 也有 XML 的好处, 比如使用 SAX 来解析本地文件一样, 你不需要像解析 json 一样等到整个文档下载完成才开始解析. 当你处理很大的数据的时候就会极大的降低内存消耗和增加性能.
正确设定背景图片
全屏背景图, 在 View 中添加一个 UIImageView 作为一个子 View
只是某个小的 View 的背景图, 你就需要用 UIColor 的 colorWithPatternImage 来做了, 它会更快地渲染也不会花费很多内存.
减少使用 web 特性. 想要更高的性能你就要调整下你的 HTML 了, 第一件要做的事就是尽可能移除不必要的 JavaScript, 避免使用过大的框架. 能只用原生的 js 就更好了. 尽可能异步加载例如用户行为统计 script 这种不影响页面表达的 javaScript. 注意你使用的图片, 保证图片符合你使用的大小.
shadow Path. Core Animation 不得不现在后台得出你的图形并加好阴影然后渲染, 这个开销是很大的. 使用shadowPath 的话就避免了这个问题. 使用 shadow path 的话 iOS 就不必每次都计算如何渲染, 它使用一个预先计算好的路径. 但问题都是自己计算path的话可能在默写 View 中比较困难, 且每当 View 的 frame 变化的时候你都需要去update shadow path
优化 TableView
正确使用 reuseIdentifier 来重用 cell
尽量使所有的 View opaque, 包括 cell 自身
避免渐变, 图片缩放, 后台选人
缓存行高
如果 cell 内部的内容来自web, 使用异步加载, 缓存请求结果.
使用 shadowPath 来画阴影
减少 subviews 的数量
尽量不使用 cellForRowAtIndexPath: 如果你需要用到它, 只用一次然后缓存结果
使用正确的数据结构来存储数据
使用 towHeight, sectionFooterHeight 和 sectionHeaderHeight 来 设定固定的高, 不要请求delegate
选择正确的数据储存选项
NSUserDefaults: 很nice 也很便捷, 但是它只适用于小数据, 比如一些简单的布尔型的设置选项, 再大点你就要考虑其他方式了
XML 这种结构化档案: 总体来说, 你需要读取整个文件到内存里去解析, 这样是很不经济的, 适用 SAX 有事一个很麻烦的事情.
NSCoding: 也需要读取文件
在性能层面来说, SQLite 和 CoreData 是相似的, 他们的不同在于具体使用方法
Core Data 代表一个对象的 graph model, 但是 SQLite 就是一个 DBMS
Apple 在一般情况下建议使用 Core Data, 但是如果你有理由不使用它, 那么久去使用更加底层的 SQLite 吧
如果你使用 SQLite, 你就可以用FMDB 这个库来简化 SQLite 的操作, 这样你就不会花很多精力了解 SQLite 的 C API了
高级
加速启动时间. 快速打开app是很重要的, 特别是用户第一次打开它时, 对 app 来讲, 第一印象太重要了, 和人见面一样. 你能做的就是使它尽可能做更多的异步任务, 比如加载远端或者数据库数据, 解析数据. 避免过于庞大的 XIB, 因为他们是在主线程上加载的. 所以尽量使用没有这个问题的 StoryBoards. 一定要把设备从 Xcode 断奶来测试启动速度
使用 Autorelease Pool. NSAutoreleasePool 负责释放 block 中的 autoreleased Object. 一般情况下它会自动被 UIKit 调用. 但是有些情况下也需要手动穿吉他. 加入创建很多零食对象, 你会发现内存一直在减少直到这些对象被 release 的时候. 这是因为只有当 UIKit 用光了 autorelease pool 的时候 memory 才会被释放. 消息是你可以在自己的 @autoreleasepool 里创建临时的对象来避免这个行为.
选择是否缓存图片. 常见的从 bundle 中加载图片的方式有俩种, 一个是 imageNamed, 一个是 imageWithContentsOfFile,
imageNamed: 这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象如果它存在的话。如果缓存中没有找到相应的图片,这个方法从指定的文档中加载然后缓存并返回这个对象。因此imageNamed的优点是当加载时会缓存图片。所以当图片会频繁的使用时,那么用imageNamed的方法会比较好。例如:你需要在 一个TableView里的TableViewCell里都加载同样一个图标,那么用imageNamed加载图像效率很高。系统会把那个图标Cache到内存,在TableViewCell里每次利用那个图像的时候,只会把图片指针指向同一块内存。正是因此使用imageNamed会缓存图片,即将图片的数据放在内存中,iOS的内存非常珍贵并且在内存消耗过大时,会强制释放内存,即会遇到memory warnings。而在iOS系统里面释放图像的内存是一件比较麻烦的事情,有可能会造成内存泄漏。例如:当一个UIView对象的animationImages是一个装有UIImage对象动态数组NSMutableArray,并进行逐帧动画。当使用imageNamed的方式加载图像到一个动态数组NSMutableArray,这将会很有可能造成内存泄露。原因很显然的。
imageWithContentsOfFile:仅加载图片,图像数据不会缓存。因此对于较大的图片以及使用情况较少时,那就可以用该方法,降低内存消耗。
避免日期格式的转换. 如果你要用 NSDataFormatter 来处理很多日期格式, 应该小心一点. 就像之前提到的, 任何时候重用 NSDateFormatters 都是一个好的时间. 如果你可以控制你所处理的日期格式, 今年选择 Unix 时间戳. 你可以方便的从时间戳转换到 NSDate
- (NSDate*)dateFromUnixTimestamp:(NSTimeInterval)timestamp {
return[NSDate dateWithTimeIntervalSince1970:timestamp];
}
这样会比用 C 来解析日期字符串还快, 需要注意的是, 许多 web PAI 会以未免的形式返回时间戳, 因为这种格式在 javascript 中更方便使用. 记住用 dateFromUnixTimestamp 之前除以 1000 就可以了
网友评论