iOS載入單張圖片導致崩潰的分析

weixin_33912445發表於2017-02-20

1、初步分析

首先iPhone畢竟是手持裝置,它所佔有的記憶體是有限的,當圖片過大的時候會引起記憶體導致的崩潰現象。

iPhone下每個app可用的記憶體是被限制的,如果一個app使用的記憶體超過20M,則系統會向該app傳送Memory Warning訊息。收到此訊息後,app必須正確處理,否則可能出錯或者出現記憶體洩露。

2、崩潰執行的過程分析

app收到Memory Warning後會呼叫:UIApplication::didReceiveMemoryWarning -> UIApplicationDelegate::applicationDidReceiveMemoryWarning,然後呼叫當前所有的viewController進行處理。因此處理的主要工作是在viewController。

建立viewcontroller時,執行順序是loadview -> viewDidLoad。

當收到記憶體警告時,如果viewcontroller未顯示(在後臺),會執行didReceiveMemoryWarning -> viewDidUnLoad;如果viewcontroller當前正在顯示(在前臺),則只執行didReceiveMemoryWarning。

當重新顯示該viewController時,執行過viewDidUnLoad的viewcontroller(即原來在後臺)會重新呼叫loadview -> viewDidLoad。

3、圖片載入的方法分析

**仔細檢視Apple官方的文件,可見其為生成一個UIImage物件提供了兩種方法載入圖片:
**

  1. imageNamed,其引數為圖片的名字;
  2. imageWithContentsOfFile,其引數也是圖片檔案的路徑。

這兩者是有區別的,根據Apple的官方文件:
imageNamed: 這個方法用一個指定的名字在系統快取中查詢並返回一個圖片物件,如果它存在的話。如果快取中沒有找到相應的圖片,這個方法從指定的文件中載入然後快取並返回這個物件。

因此imageNamed的優點是當載入時會快取圖片。所以當圖片會頻繁的使用時,那麼用imageNamed的方法會比較好。

例如:你需要在 一個TableView裡的TableViewCell裡都載入同樣一個圖示,那麼用imageNamed載入影象效率很高。系統會把那個圖示Cache到記憶體,在TableViewCell裡每次利用那個影象的時候,只會把圖片指標指向同一塊記憶體。正是因此使用imageNamed會快取圖片,即將圖片的資料放在記憶體中,iOS的記憶體非常珍貴並且在記憶體消耗過大時,會強制釋放記憶體,即會遇到memory warnings。

而在iOS系統裡面釋放影象的記憶體是一件比較麻煩的事情,有可能會造成記憶體洩漏。

例如:當一個UIView物件的animationImages是一個裝有UIImage物件動態陣列NSMutableArray,並進行逐幀動畫。當使用imageNamed的方式載入影象到一個動態陣列NSMutableArray,這將會很有可能造成記憶體洩露,原因很顯然的。

imageWithContentsOfFile:僅載入圖片,影象資料不會快取。

因此對於較大的圖片以及使用情況較少時,那就可以用該方法,降低記憶體消耗。

//下面列舉出兩種方法載入UIImage的用法:
NSString *path = [[NSBundle mainBundle] pathForResource:@”icon” ofType:@”png”];
UIImage *image = [UIImage imageWithContentsOfFile:path];

NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:“png”];
NSData *image = [NSData dataWithContentsOfFile:filePath];
UIImage *image = [UIImage imageWithData:image]; //or = [UIImage imageWithContentsOfFile:filePath];

相比較而言,這其中的關鍵在於以下:

//imageWithContentsOfFile:僅載入圖片,影象資料不會快取
//imageNamed:先將圖片快取到記憶體中,然後在顯示。

最後,再次強調兩種用法各有各的優點,需要針對具體的應用場景來使用才能恰到好處。

相關文章