潛伏期值得思考 - 凱文 帕薩特git
在第13章「高效繪圖」中,咱們研究了和Core Graphics繪圖相關的性能問題,以及如何修復。和繪圖性能相關緊密相關的是圖像性能。在這一章中,咱們將研究如何優化從閃存驅動器或者網絡中加載和顯示圖片。github
繪圖實際消耗的時間一般並非影響性能的因素。圖片消耗很大一部份內存,並且不太可能把須要顯示的圖片都保留在內存中,因此須要在應用運行的時候週期性地加載和卸載圖片。網絡
圖片文件加載的速度被CPU和IO(輸入/輸出)同時影響。iOS設備中的閃存已經比傳統硬盤快不少了,但仍然比RAM慢將近200倍左右,這就須要很當心地管理加載,來避免延遲。工具
只要有可能,試着在程序生命週期不易察覺的時候來加載圖片,例如啓動,或者在屏幕切換的過程當中。按下按鈕和按鈕響應事件之間最大的延遲大概是200ms,這比動畫每一幀切換的16ms小得多。你能夠在程序首次啓動的時候加載圖片,可是若是20秒內沒法啓動程序的話,iOS檢測計時器就會終止你的應用(並且若是啓動大於2,3秒的話用戶就會抱怨了)。oop
有些時候,提早加載全部的東西並不明智。好比說包含上千張圖片的圖片傳送帶:用戶但願可以可以平滑快速翻動圖片,因此就不可能提早預加載全部圖片;那樣會消耗太多的時間和內存。性能
有時候圖片也須要從遠程網絡鏈接中下載,這將會比從磁盤加載要消耗更多的時間,甚至可能因爲鏈接問題而加載失敗(在幾秒鐘嘗試以後)。你不可以在主線程中加載網絡形成等待,因此須要後臺線程。優化
在第12章「性能調優」咱們的聯繫人列表例子中,圖片都很是小,因此能夠在主線程同步加載。可是對於大圖來講,這樣作就不太合適了,由於加載會消耗很長時間,形成滑動的不流暢。滑動動畫會在主線程的run loop中更新,因此會有更多運行在渲染服務進程中CPU相關的性能問題。動畫
清單14.1顯示了一個經過 UICollectionView 實現的基礎的圖片傳送器。圖片在主線程中 -collectionView:cellForItemAtIndexPath: 方法中同步加載(見圖14.1)。atom
清單14.1 使用UICollectionView
實現的圖片傳送器spa
#import "ViewController.h"@interface ViewController() <UICollectionViewDataSource>@property (nonatomic, copy) NSArray *imagePaths; @property (nonatomic, weak) IBOutlet UICollectionView *collectionView;@end@implementation ViewController- (void)viewDidLoad { //set up data self.imagePaths = [[NSBundle mainBundle] pathsForResourcesOfType:@"png" inDirectory:@"Vacation Photos"]; //register cell class [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"Cell"]; }- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return [self.imagePaths count]; }- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { //dequeue cell UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; //add image view const NSInteger imageTag = 99; UIImageView *imageView = (UIImageView *)[cell viewWithTag:imageTag]; if (!imageView) { imageView = [[UIImageView alloc] initWithFrame: cell.contentView.bounds]; imageView.tag = imageTag; [cell.contentView addSubview:imageView]; } //set image NSString *imagePath = self.imagePaths[indexPath.row]; imageView.image = [UIImage imageWithContentsOfFile:imagePath]; return cell; }@end
圖14.1 運行中的圖片傳送器
傳送器中的圖片尺寸爲800x600像素的PNG,對iPhone5來講,1/60秒要加載大概700KB左右的圖片。當傳送器滾動的時候,圖片也在實時加載,因而(預期中的)卡動就發生了。時間分析工具(圖14.2)顯示了不少時間都消耗在了 UIImage 的 +imageWithContentsOfFile: 方法中了。很明顯,圖片加載形成了瓶頸。