iOS开发基础73-24种性能优化技巧
在iOS开发中,性能优化是提升用户体验、提高应用响应速度和资源利用率的关键。本文将详细介绍从ARC到View控制在内的一系列优化技巧,帮助开发者在项目升级或开发中避免性能瓶颈。
1. 使用ARC管理内存
自动引用计数(Automatic Reference Counting, ARC)和iOS 5一起发布,它自动为你管理retain
和release
的过程,从而避免由于忘记释放内存而导致的内存泄漏。ARC不仅提高了代码的可读性,还减少了手动管理内存的复杂性。ARC通过编译器插入的代码,在对象不再被引用时自动释放内存,提高了应用性能。
2. 在正确的地方使用 reuseIdentifier
在UITableView及UICollectionView中,复用标识符reuseIdentifier
极为重要。复用机制避免了频繁创建和销毁视图,从而显著提升性能。
示例代码:
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
dequeueReusableCellWithIdentifier 方法会重用现有的cell,或在必要时创建新的cell。如果不使用reuseIdentifier
,每次显示新行都需要创建一个cell,大大降低滚动性能。
3. 尽量将Views设置为不透明(opaque)
如果view是完全不透明的,将其opaque
属性设置为YES
,渲染系统会进行优化,从而提高性能。这个属性在Interface Builder或代码中都可以设置。
view.opaque = YES;
在模拟器中可以通过Debug -> Color Blended Layers来查看哪些views没有设置为opaque。
4. 避免过于庞大的XIB
尽管iOS 5 之后Storyboards变得越来越流行,但XIB在某些场景中仍然有用。应尽量减少XIB的体积,将每个View Controller的view层次结构分散到单独的XIB中。加载XIB时,所有内容都会被放入内存,包括不立即使用的资源,造成内存浪费。
5. 不要阻塞主线程
主线程用于UI渲染和事件处理,阻塞主线程会导致应用无响应。在进行任何耗时操作时,应使用后台线程或异步处理方法。
示例代码:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行耗时操作
dispatch_async(dispatch_get_main_queue(), ^{
// 更新UI
});
});
6. 在Image Views中调整图片大小
确保图片大小与UIImageView的尺寸匹配,避免运行时缩放造成的性能损耗。如果图片来自远程服务,可以在下载完成后进行一次性缩放。
UIGraphicsBeginImageContext(view.frame.size);
[image drawInRect:view.bounds];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
7. 选择正确的Collection
不同数据集合(Collection)在不同场景有不同的性能表现:
NSArray
:有序,索引查找快,值查找慢。NSDictionary
:键值对,键查找快。NSSet
:无序,值查找快,插入和删除快。
8. 打开gzip压缩
开启gzip压缩可以大大减小从服务器下载的数据量,提高传输效率。iOS的NSURLConnection默认支持gzip压缩。
9. 重用和延迟加载(lazy load)Views
避免一次性创建所有subview,应在需要时才创建,从而节省内存。例如,UITableView和UICollectionView会在需要时才创建cell,使得内存利用率更高。
10. 缓存策略
对无频繁变化但需多次读取的资源进行缓存,例如远程服务器的响应、图片或计算结果。使用NSCache
可以在内存不足时自动清理缓存。
11. 权衡渲染方法
在iOS中,有多种方法渲染复杂UI。优先使用预渲染的图片而非代码绘制,可以减少CPU和内存使用,但需要权衡应用体积的增加。
12. 处理内存警告
系统在内存不足时会发出警告,应用需要响应这些警告释放不必要的内存资源。覆盖UIViewController的didReceiveMemoryWarning
方法,移除不可见view及缓存数据。
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// 移除缓存数据
}
13. 重用大开销对象
对于一些创建开销大的对象,如NSDateFormatter
和NSCalendar
,应尽量重用。
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
- (NSDateFormatter *)dateFormatter {
if (!_dateFormatter) {
_dateFormatter = [[NSDateFormatter alloc] init];
_dateFormatter.dateFormat = @"yyyy-MM-dd";
}
return _dateFormatter;
}
14. 使用Sprite Sheets
Sprite sheet通过将多个图像合并成一张大图,使用一个纹理来渲染多张图片,大大提高渲染性能和内存使用效率。
15. 避免反复处理数据
在读取远程数据时,尽量使用适合展示的数据结构,避免在客户端进行多次转换,提高效率。
16. 选择正确的数据格式
解析JSON通常比XML更快,且JSON数据通常更小,传输效率更高。iOS 5之后的内置JSON解析器进一步提高了处理效率。不过,XML适用于处理大批量数据和流媒体。
17. 正确设定背景图片
通过UIImageView
设置大背景图,或通过UIColor
的colorWithPatternImage
方法设置小的平铺背景图,节省内存,提高渲染速度。
18. 减少使用Web特性
UIWebView 远没有 Safari迅速,尽量减少JavaScript使用并异步加载。确保图像大小合适,避免过大的图像文件。
19. 设定Shadow Path
为视图的阴影设置shadowPath,避免每次渲染时重新计算,提高性能。
view.layer.shadowPath = [UIBezierPath bezierPathWithRect:view.bounds].CGPath;
20. 优化Table View
确保流畅的TableView滚动,正确使用reuseIdentifier
、设置view的opaque属性、避免图片缩放,使用异步加载,减少subviews数量。
21. 选择合适的数据存储选项
选择合适的数据存储方式:NSUserDefaults适用小数据,SQL和Core Data适用于复杂数据结构和频繁查询的场景。使用FMDB库简化SQLite操作。
22. 使用Autorelease Pool
在创建大量临时对象时,手动创建autorelease pool,防止内存持续增长。
@autoreleasepool {
// 创建大量临时对象
}
23. 选择是否缓存图片
需要反复使用的图片应使用imageNamed
方法加载并缓存。如果图片用于一次性展示,应使用imageWithContentsOfFile
方法避免浪费内存。
24. 避免日期格式转换
优先使用Unix时间戳,避免频繁使用NSDateFormatter。如果必须使用NSDateFormatter,确保重用实例。