下載超大檔案和下載小檔案有何不同?同樣是下載的動作,這時候就要考慮到時間和空間。
若考慮時間,用3G下載通常比用WiFi下載慢很多,於是下載時間就會拉長,只要有足夠的時間一樣可以下載完畢,然而問題在於下載的狀態又分前景模式和背景模式,前景模式下載只要設備有足夠電源就能完成下載,背景模式下載就要考慮要在限定的時間內下載完畢。可以參考我剛寫的文章:爭取背景執行時間。
若考慮空間,硬碟當然要有足夠的空間可容納檔案,主要的議題是在於從網路傳輸資料,會先暫存於記憶體,而iOS分配給每個APP記憶體有限,以目前iPhone記憶體1G的情況來看,一個APP能獲得500MB的額度就很多了,若我想下載一個超過500MB的檔案就有記憶體會爆掉的危機,那我們可以怎麼做呢?
我這裡的做法是,每當delegate取得些許資料的時候,就將記憶體裡的資料儲存到硬碟中,陸續將之後的資料附加於已存在硬碟中檔案的後方,逐漸拼成一個完整的檔案,如此記憶體使用量就能維持在低量。
我找到兩種方法可用,法一:
/** Theme: Download big file IDE: Xcode 5 Language: Objective C Date: 103/04/09 Author: HappyMan Blog: https://cg2010studio.wordpress.com/ */ - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { NSOutputStream *stream = [[NSOutputStream alloc] initToFileAtPath:downloadTargetPath append:YES]; [stream open]; NSUInteger left = [data length]; NSUInteger nwr = 0; do { nwr = [stream write:[data bytes] maxLength:left]; if (-1 == nwr) break; left -= nwr; } while (left > 0); if (left) { NSLog(@"stream error: %@", [stream streamError]); } [stream close]; }
上頭的方法有點奇妙,我們來看法二:
/** Theme: Download big file IDE: Xcode 5 Language: Objective C Date: 103/04/09 Author: HappyMan Blog: https://cg2010studio.wordpress.com/ */ // HTFileManager.h @interface HTFileManager : NSObject { NSFileHandle *fileHandle; } // HTFileManager.m - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { fileHandle = nil; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { if(fileHandle) { // 找到檔案的尾巴 [fileHandle seekToEndOfFile]; } else { // 建立檔案的URL [[NSFileManager defaultManager] createFileAtPath:downloadTargetPath contents:nil attributes:nil]; // 初始化檔案處理 fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:downloadTargetPath]; } // 寫入資料到硬碟 [fileHandle writeData:data]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { // 關閉檔案處理 [fileHandle closeFile]; }
看來上述程式碼一看就懂!然而兩者有異曲同工之妙,效果差不多~
這裡有三個delegate,下載檔案陸續會執行:
- didReceiveResponse (一次)
- didReceiveData (多次)
- didFinishLoading (一次)
接下來我們怎麼知道,網路傳輸的資料真的有從記憶體轉換到硬碟中?好,可以開啟Xcode提供的工具Instruments,實際去執行APP,然後下載超大檔案試試看!
最後想說的是,使用不同的工具來檢測效果是較好的做法,我在Xcode編譯好在實機或模擬器上跑,Debug Gauges顯示的記憶體使用量會不斷往上攀升,然而同樣的測試過程,使用Instruments就沒有令人無奈的現象,是比較符合使用者真實情況。
參考:Downloading a Large File – iPhone SDK、How to download a large file with the iPhone SDK and avoid memory usage issues?。
Comments on: "[iOS] 下載超大檔案" (2)
[…] 像是超大影片(例如100MB)要下載,就不能先全部載到記憶體,再轉存到硬碟,而是要每下載一小部分就從記憶體轉存到硬碟,以免超過App所能乘載的記憶體量而崩潰。 […]
讚讚
[…] 像是超大影片(例如100MB)要下載,就不能先全部載到記憶體,再轉存到硬碟,而是要每下載一小部分就從記憶體轉存到硬碟,以免超過App所能乘載的記憶體量而崩潰。 […]
讚讚