下載超大檔案和下載小檔案有何不同?同樣是下載的動作,這時候就要考慮到時間和空間。
若考慮時間,用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所能乘載的記憶體量而崩潰。 […]
讚讚