NSURLConnection簡介
- NSURLConnection是2003年隨著第一版Safari的發(fā)布而發(fā)布的金句,它不單單是一個網(wǎng)絡(luò)請求類,而是指代Foundation框架的URL系統(tǒng)中的一系列關(guān)聯(lián)的組件:NSURLRequest暖释、NSURLResponse、NSURLProtocol稠肘、NSHTTPCookieStorage斥黑、NSURLCredentialStorage以及同名類NSURLConnection。
- 從iOS9開始埃跷,NSURLConnection中發(fā)送請求的兩個方法已經(jīng)過期(同步請求蕊玷,異步請求),初始化網(wǎng)絡(luò)連接的方法也被設(shè)置為過期,系統(tǒng)不再推薦使用弥雹,蘋果建議使用NSURLSession發(fā)送網(wǎng)絡(luò)請求。
簡單下載
使用NSURLConnection實現(xiàn)簡單下載只需三步
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos/IMG_3928.MOV"];
//創(chuàng)建請求對象request
/*
1. cachePolicy - 緩存策略
- NSURLRequestUseProtocolCachePolicy = 0,
-(常用)默認(rèn)緩存策略延届,若使用requestWithURL方法剪勿,默認(rèn)使用該緩存策略;它會根據(jù)HTTP頭中的信息進(jìn)行緩存處理方庭,服務(wù)器可以在HTTP頭中加入Expires和Cache-Control等來告訴客戶端應(yīng)該施行的緩存策略厕吉。
- NSURLRequestReloadIgnoringLocalCacheData = 1,
-(偶爾使用)顧名思義,忽略本地緩存械念,直接加載服務(wù)器數(shù)據(jù)
- NSURLRequestReturnCacheDataElseLoad = 2,
-(不用)一直嘗試讀取緩存數(shù)據(jù)头朱,若沒有緩存,才會去請求網(wǎng)絡(luò)龄减,該策略的重大缺陷是無法直到緩存的刷新時機(jī)项钮。
- NSURLRequestReturnCacheDataDontLoad = 3,
- (不用)該策略之讀取緩存數(shù)據(jù),無論何時都不會進(jìn)行網(wǎng)絡(luò)請求。
2. timeoutInterval - 超時時間 一般設(shè)置在15-30秒 AFNetworking中超時時間默認(rèn)60s
*/
NSURLRequest *req = [NSURLRequest requestWithURL:url cachePolicy:(NSURLRequestUseProtocolCachePolicy) timeoutInterval:15];
//連接服務(wù)器烁巫,發(fā)送網(wǎng)絡(luò)請求
/*
queue - 這里使用主線程還是子線程由執(zhí)行的代碼塊決定
該參數(shù)決定block代碼塊在哪個線程上執(zhí)行署隘,若block中有刷新UI的操作,則必須放在主線程上執(zhí)行亚隙;若有一些耗時操作磁餐,則放在子線程上執(zhí)行
*/
//開始下載
[NSURLConnection sendAsynchronousRequest:req queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
//下載完成,將數(shù)據(jù)寫入磁盤
/*
atomically 原子屬性阿弃,保證線程安全
*/
[data writeToFile:@"/Users/jsby-yf007/Desktop/test.MOV" atomically:YES];
NSLog(@"下載完成");
}];
下載完成后诊霹,可以在命令行通過獲取文件的MD5來驗證文件是否下載完整上面代碼在實際開發(fā)中所帶來的問題
1.內(nèi)存會暴漲,出現(xiàn)一個峰值
圖2
出現(xiàn)圖2的情況是因為NSURLConnection下載文件時渣淳,先是將整個文件下載到內(nèi)存脾还,然后再寫入到沙盒,如果文件比較大水由,就會出現(xiàn)內(nèi)存暴漲的情況荠呐。在執(zhí)行
[data writeToFile:@"/Users/jsby-yf007/Desktop/test.MOV" atomically:YES];
這句代碼的時候,data是整個文件的完整數(shù)據(jù)砂客,在文件寫入的過程中泥张,data是存在于內(nèi)存中的,然后一次性寫入到本地鞠值,如此大的數(shù)據(jù)存入內(nèi)存中媚创,當(dāng)然會出現(xiàn)內(nèi)存暴增的情況,當(dāng)寫入完成后彤恶,系統(tǒng)會自動釋放這些內(nèi)存钞钙,所以會出現(xiàn)一個內(nèi)存峰值。本例中的視頻文件只有兩百多兆声离,所以不會出現(xiàn)crash芒炼,但是要是下載一個十幾個G的文件的時候,不用想术徊,肯定crash本刽!
2.沒有下載進(jìn)度以及暫停/繼續(xù)
在實際開發(fā)中,要下載一個很大的文件赠涮,沒有下載進(jìn)度和暫停/繼續(xù)子寓,基本是不可能順利的下載下來的,大大影響用戶體驗笋除!
設(shè)置代理實現(xiàn)下載
使用代理實現(xiàn)進(jìn)度跟進(jìn)
- 在響應(yīng)方法中獲取到文件總大小斜友。
- 在接收數(shù)據(jù)的方法中,根據(jù)每次接收到的數(shù)據(jù)長度計算數(shù)據(jù)的總進(jìn)度垃它。
設(shè)置代理<NSURLConnectionDataDelegate>
//設(shè)置請求路徑url
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos/IMG_3928.MOV"];
//添加請求request
/*
1. cachePolicy - 緩存策略
- NSURLRequestUseProtocolCachePolicy = 0,
-(常用)默認(rèn)緩存策略鲜屏,若使用requestWithURL方法烹看,默認(rèn)使用該緩存策略;它會根據(jù)HTTP頭中的信息進(jìn)行緩存處理墙歪,服務(wù)器可以在HTTP頭中加入Expires和Cache-Control等來告訴客戶端應(yīng)該施行的緩存策略听系。
- NSURLRequestReloadIgnoringLocalCacheData = 1,
-(偶爾使用)顧名思義,忽略本地緩存虹菲,直接加載服務(wù)器數(shù)據(jù)
- NSURLRequestReturnCacheDataElseLoad = 2,
-(不用)一直嘗試讀取緩存數(shù)據(jù)靠胜,若沒有緩存,才會去請求網(wǎng)絡(luò)毕源,該策略的重大缺陷是無法直到緩存的刷新時機(jī)浪漠。
- NSURLRequestReturnCacheDataDontLoad = 3,
- (不用)該策略之讀取緩存數(shù)據(jù),無論何時都不會進(jìn)行網(wǎng)絡(luò)請求霎褐。
2. timeoutInterval - 超時時間 一般設(shè)置在15-30秒 AFNetworking中超時時間默認(rèn)60s
*/
NSURLRequest *req = [NSURLRequest requestWithURL:url cachePolicy:(NSURLRequestUseProtocolCachePolicy) timeoutInterval:15];
//3.創(chuàng)建連接并設(shè)置代理
NSURLConnection *conn = [NSURLConnection connectionWithRequest:req delegate:self];
//4.啟動連接
[conn start];
實現(xiàn)NSURLConnectionDataDelegate的幾個代理方法
#pragma mark - <NSURLConnectionDataDelegate>
//1.接收服務(wù)器的響應(yīng) -- 服務(wù)器的狀態(tài)行&響應(yīng)頭 做一些準(zhǔn)備工作
/*
NSURLResponse
- expectedContentLength 服務(wù)器給的預(yù)期數(shù)據(jù)長度 long long 類型
- suggestedFilename 服務(wù)器建議保存的文件名稱 NSString 類型
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.expectedContentLength = response.expectedContentLength;
self.currentLength = 0;
}
//2.接收服務(wù)器的數(shù)據(jù) -- 此代理方法可能會調(diào)用多次址愿,因為服務(wù)器返回數(shù)據(jù)是將數(shù)據(jù)拆分成很多段,分段返回給客戶端
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
self.currentLength += data.length;
float progress = (float)self.currentLength/self.expectedContentLength;
NSLog(@"下載進(jìn)度%f",progress);
}
//3.所有數(shù)據(jù)接收完成 -- 最后的通知
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"下載完成");
}
//4.下載失敗或出現(xiàn)錯誤
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"出錯了6沉АO煳健!");
}
為實現(xiàn)進(jìn)度跟進(jìn)省艳,聲明兩個變量
/* 文件總大小 */
@property (nonatomic, assign) long long expectedContentLength;
/* 當(dāng)前已下載的文件大小 */
@property (nonatomic, assign) long long currentLength;
以上代碼即可實現(xiàn)下載進(jìn)度跟進(jìn)
使用代理實現(xiàn)數(shù)據(jù)保存
先拼接數(shù)據(jù)娘纷,再寫入
這里我們先聲明兩個變量
/* 保存的目標(biāo)路徑 */
@property (nonatomic, copy) NSString *saveFilePath;
/* 保存的數(shù)據(jù) */
@property (nonatomic, strong) NSMutableData *saveData;
接下來,我們在代理方法中實現(xiàn)數(shù)據(jù)的保存
#pragma mark - <NSURLConnectionDataDelegate>
//1.接收服務(wù)器的響應(yīng) -- 服務(wù)器的狀態(tài)行&響應(yīng)頭 做一些準(zhǔn)備工作
/*
NSURLResponse
- expectedContentLength 服務(wù)器給的預(yù)期數(shù)據(jù)長度 long long 類型
- suggestedFilename 服務(wù)器建議保存的文件名稱 NSString 類型
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.expectedContentLength = response.expectedContentLength;
self.currentLength = 0;
//設(shè)置保存的目標(biāo)路徑
self.saveFilePath = [@"/Users/jsby-yf007/Desktop" stringByAppendingPathComponent:response.suggestedFilename];
}
- (NSMutableData *)saveData
{
if (!_saveData) {
_saveData = [[NSMutableData alloc] init];
}
return _saveData;
}
//2.接收服務(wù)器的數(shù)據(jù) -- 此代理方法可能會調(diào)用多次跋炕,因為服務(wù)器返回數(shù)據(jù)是將數(shù)據(jù)拆分成很多段赖晶,分段返回給客戶端
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
self.currentLength += data.length;
float progress = (float)self.currentLength/self.expectedContentLength;
NSLog(@"下載進(jìn)度%f",progress);
//將獲取到的數(shù)據(jù)拼接
[self.saveData appendData:data];
}
//3.所有數(shù)據(jù)接收完成 -- 最后的通知
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//將數(shù)據(jù)寫入磁盤
[self.saveData writeToFile:self.saveFilePath atomically:YES];
//由于saveData為strong類型,使用完之后不會立即釋放辐烂,故遏插,需手動置nil
self.saveData = nil;
NSLog(@"下載完成");
}
//4.下載失敗或出現(xiàn)錯誤
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"出錯了!>佬蕖胳嘲!");
}
以上代碼實現(xiàn)了數(shù)據(jù)的保存,但我們發(fā)現(xiàn)扣草,內(nèi)存依然會出現(xiàn)暴增由此我們可以推斷胎围,蘋果的sendAsynchronousRequest異步方法內(nèi)部也是通過這種方式來實現(xiàn)文件的保存
邊下載,邊保存
從上面的代碼中我們發(fā)現(xiàn)德召,將數(shù)據(jù)統(tǒng)一拼接好后再寫入依然會出現(xiàn)內(nèi)存暴增的情況,所以汽纤,邊下載上岗,變保存不失為一個比較好的辦法,因為每段數(shù)據(jù)的長度比較小蕴坪,保存完之后肴掷,再釋放這部分內(nèi)存敬锐,顧不會出現(xiàn)內(nèi)存暴增的情況!
1. 使用NSFileHandle實現(xiàn)
#pragma mark - <NSURLConnectionDataDelegate>
//1.接收服務(wù)器的響應(yīng) -- 服務(wù)器的狀態(tài)行&響應(yīng)頭 做一些準(zhǔn)備工作
/*
NSURLResponse
- expectedContentLength 服務(wù)器給的預(yù)期數(shù)據(jù)長度 long long 類型
- suggestedFilename 服務(wù)器建議保存的文件名稱 NSString 類型
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.expectedContentLength = response.expectedContentLength;
self.currentLength = 0;
//設(shè)置保存的目標(biāo)路徑
self.saveFilePath = [@"/Users/jsby-yf007/Desktop" stringByAppendingPathComponent:response.suggestedFilename];
/*
在使用NSFileHandle進(jìn)行文件保存的時候呆瞻,若文件已存在台夺,繼續(xù)保存的話,數(shù)據(jù)將繼續(xù)向后拼接痴脾;
因此颤介,這里采用比較粗暴的方式,直接刪除已存在的文件(實際開發(fā)中不建議這么做)
在實際開發(fā)中赞赖,我們可以使用NSFileManager對文件進(jìn)行一系列的判斷
*/
[[NSFileManager defaultManager] removeItemAtPath:self.saveFilePath error:nil];
}
//2.接收服務(wù)器的數(shù)據(jù) -- 此代理方法可能會調(diào)用多次滚朵,因為服務(wù)器返回數(shù)據(jù)是將數(shù)據(jù)拆分成很多段,分段返回給客戶端
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
self.currentLength += data.length;
float progress = (float)self.currentLength/self.expectedContentLength;
NSLog(@"下載進(jìn)度%f",progress);
//將獲取到的數(shù)據(jù)拼接
[self writeToFileWithData:data];
}
/*
將數(shù)據(jù)寫入文件 -- 將每段數(shù)據(jù)按順序?qū)懭胛募ㄆ唇訑?shù)據(jù))
NSFileManager - 文件管理器前域,主要功能:創(chuàng)建目錄辕近,檢查目錄或文件是否存在,刪除目錄或文件匿垄,遍歷目錄移宅。。椿疗。 主要是針對文件的操作 類似于Mac中的Finder
NSFileHandle - 文件“句柄”(文件指針)對同一文件二進(jìn)制的讀/寫操作
這里使用 NSFileHandle 來進(jìn)行文件的寫入
*/
- (void)writeToFileWithData:(NSData *)data
{
/*
NSFileHandle也是對文件指針的操作
注意:當(dāng)self.saveFilePath目錄下的文件不存在時漏峰,fileHandleForWritingAtPath方法返回的NSFileHandle對象為nil,因此变丧,我們在使用時芽狗,需要進(jìn)行判斷
*/
NSFileHandle *fp = [NSFileHandle fileHandleForWritingAtPath:self.saveFilePath];
//判斷文件是否存在,NSFileHandle是對文件的操作痒蓬,因此童擎,我們先寫入一段數(shù)據(jù)到磁盤
if (fp == nil) {
//如果文件不存,我們先執(zhí)行寫入操作
[data writeToFile:self.saveFilePath atomically:YES];
} else {
//如果文件存在攻晒,將data追加到文件的末尾(拼接)
/*
NSFileHandle指針默認(rèn)指向文件的起始位置顾复,當(dāng)我們需要追加數(shù)據(jù)的時候,首先我們需要將文件指針指向文件的末尾鲁捏,這里芯砸,NSFileHandle為我們提供了一個方法seekToEndOfFile,可以將指針移向文件的末尾
*/
[fp seekToEndOfFile];
//寫入文件 NSFileHandle 提供了寫入文件的方法
[fp writeData:data];
//關(guān)閉 -- 在c語言開發(fā)中给梅,關(guān)于文件的讀假丧、寫操作,都會涉及到文件的打開和關(guān)閉动羽;這里是為了文件數(shù)據(jù)的安全包帚,同時不關(guān)閉打開的文件會占用系統(tǒng)資源
[fp closeFile];
}
}
//3.所有數(shù)據(jù)接收完成 -- 最后的通知
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"下載完成");
}
//4.下載失敗或出現(xiàn)錯誤
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"出錯了!T讼拧渴邦!");
}
以上是使用NSFileHandle來實現(xiàn)的數(shù)據(jù)寫入操作疯趟,其中,data只是一個局部變量谋梭,使用完即釋放信峻,文件是分段寫入,則不會出現(xiàn)內(nèi)存暴增(圖4)2. 使用NSOutputStream實現(xiàn)
NSOutputStream文件輸出流寫入文件的方式是瓮床,每段數(shù)據(jù)會自動向后追加盹舞,不需要像NSFileHandle一樣操作指針來追加數(shù)據(jù)
先聲明一個文件的輸出流對象
/* 文件的輸出流 */
@property (nonatomic, strong) NSOutputStream *fileStream;
代理中的實現(xiàn)
#pragma mark - <NSURLConnectionDataDelegate>
//1.接收服務(wù)器的響應(yīng) -- 服務(wù)器的狀態(tài)行&響應(yīng)頭 做一些準(zhǔn)備工作
/*
NSURLResponse
- expectedContentLength 服務(wù)器給的預(yù)期數(shù)據(jù)長度 long long 類型
- suggestedFilename 服務(wù)器建議保存的文件名稱 NSString 類型
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.expectedContentLength = response.expectedContentLength;
self.currentLength = 0;
//設(shè)置保存的目標(biāo)路徑
self.saveFilePath = [@"/Users/jsby-yf007/Desktop" stringByAppendingPathComponent:response.suggestedFilename];
/*
在使用NSFileHandle進(jìn)行文件保存的時候,若文件已存在,繼續(xù)保存的話,數(shù)據(jù)將繼續(xù)向后拼接售葡;
因此棠涮,這里采用比較粗暴的方式,直接刪除已存在的文件(實際開發(fā)中不建議這么做)
在實際開發(fā)中,我們可以使用NSFileManager對文件進(jìn)行一系列的判斷
*/
[[NSFileManager defaultManager] removeItemAtPath:self.saveFilePath error:nil];
//創(chuàng)建輸出流 append(追加)
self.fileStream = [[NSOutputStream alloc] initToFileAtPath:self.saveFilePath append:YES];
//打開輸出流
[self.fileStream open];
}
//2.接收服務(wù)器的數(shù)據(jù) -- 此代理方法可能會調(diào)用多次,因為服務(wù)器返回數(shù)據(jù)是將數(shù)據(jù)拆分成很多段,分段返回給客戶端
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
self.currentLength += data.length;
float progress = (float)self.currentLength/self.expectedContentLength;
NSLog(@"下載進(jìn)度%f",progress);
//將數(shù)據(jù)追加到文件流中
/*
第一個參數(shù) uint8_t *類型 數(shù)據(jù)的傳輸都是通過二進(jìn)制流的方式傳輸蓬豁,uint8_t即8位也就是一個ASCII值,該參數(shù)是一個數(shù)組類型菇肃,NSData提供了一個屬性bytes
第二個參數(shù) 即數(shù)據(jù)長度
*/
[self.fileStream write:data.bytes maxLength:data.length];
}
//3.所有數(shù)據(jù)接收完成 -- 最后的通知
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 數(shù)據(jù)流寫入完畢后地粪,關(guān)閉輸出流
[self.fileStream close];
NSLog(@"下載完成");
}
//4.下載失敗或出現(xiàn)錯誤
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"出錯了!K霭蟆技!");
}
NSURLConnection在多線程下的問題
在我們使用NSURLConnection的異步方法時,下載小文件沒有問題斗忌,當(dāng)我們下載大文件時质礼,出現(xiàn)了內(nèi)存暴增的問題,為解決此問題织阳,我們使用了NSURLConnection的代理方法眶蕉,但是我們在使用代理方法時,缺忽略了線程問題唧躲,那么接下來造挽,問題來了,我們知道弄痹,NSURLConnection的代理默認(rèn)是在主線程中執(zhí)行的饭入,但是,為了不阻塞UI肛真,我們需要將執(zhí)行放在子線程上圣拄,查看NSURLConnection的方法,我們發(fā)現(xiàn)毁欣,NSURLConnection提供了一個方法
- (void)setDelegateQueue:(nullable NSOperationQueue*) queue
靈機(jī)一動庇谆,我們可以在創(chuàng)建連接的之后,開始連接之前來設(shè)置一下DelegateQueue將其放入新建隊列中也就是子線程中
[conn setDelegateQueue:[[NSOperationQueue alloc] init]];
但是F敬7苟!經(jīng)過測試执解,我們發(fā)現(xiàn)寞肖,問題依然存在,測試發(fā)現(xiàn)衰腌,在下載過程中新蟆,UI的操作會阻塞下載
查看connectionWithRequest:方法的注釋發(fā)現(xiàn)這么一句話
For the connection to work correctly, the calling thread’s run loop must be operating in the default run loop mode.
翻譯:為了使連接正常工作,調(diào)用線程的runloop必須在默認(rèn)runloop模式下運行
也就是說右蕊,我們創(chuàng)建NSURLConnection連接是在哪個模式下運行琼稻,下載任務(wù)就在哪個線程
setDelegateQueue這個方法只是將代理方法中的任務(wù)放入了子線程中執(zhí)行,下載任務(wù)仍然在主線程中饶囚!
接下來要如何解決這個問題呢帕翻??萝风?
我們首先想到的是嘀掸,將整個下載任務(wù)放在子線程中
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"開始了");
//1.設(shè)置請求路徑url
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos/IMG_3928.MOV"];
//2.創(chuàng)建請求
NSURLRequest *req = [NSURLRequest requestWithURL:url cachePolicy:(NSURLRequestUseProtocolCachePolicy) timeoutInterval:15];
//3.創(chuàng)建連接并設(shè)置代理
NSURLConnection *conn = [NSURLConnection connectionWithRequest:req delegate:self];
//將代理任務(wù)放在子線程中執(zhí)行
[conn setDelegateQueue:[[NSOperationQueue alloc] init]];
//4.啟動連接
[conn start];
NSLog(@"結(jié)束了");
});
執(zhí)行完上面的語句后,我們會發(fā)現(xiàn)规惰,下載任務(wù)根本沒執(zhí)行睬塌;這個問題涉及到了一個知識點runloop!每個線程都有一個實際已經(jīng)存在的runloop(運行循環(huán))歇万。但是揩晴,子線程的runloop默認(rèn)不開啟!
那解決方案出來了堕花,我們可以手動來開啟文狱。這里使用coreFoundation框架CFRunLoopRef
1.首先聲明一個CFRunLoopRef
/* 下載所在線程的runloop */
@property (nonatomic, assign) CFRunLoopRef downloadRunLoop;
2.啟動runloop
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"開始了");
//1.設(shè)置請求路徑url
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos/IMG_3928.MOV"];
//2.創(chuàng)建請求
NSURLRequest *req = [NSURLRequest requestWithURL:url cachePolicy:(NSURLRequestUseProtocolCachePolicy) timeoutInterval:15];
//3.創(chuàng)建連接并設(shè)置代理
NSURLConnection *conn = [NSURLConnection connectionWithRequest:req delegate:self];
//將代理任務(wù)放在子線程中執(zhí)行
[conn setDelegateQueue:[[NSOperationQueue alloc] init]];
//4.啟動連接
[conn start];
//5.啟動runloop
/*
使用coreFoundation框架 中的 CFRunLoopRef
其中有三個我們需要用到的方法
CFRunLoopRun 啟動當(dāng)前線程的runloop
CFRunLoopStop 停止指定線程的runloop
CFRunLoopGetCurrent 拿到當(dāng)前線程的runloop
*/
//1.拿到當(dāng)前線程的runloop
self.downloadRunLoop = CFRunLoopGetCurrent();
//2.啟動runloop
CFRunLoopRun();
NSLog(@"結(jié)束了");
});
3.停止runloop
//3.所有數(shù)據(jù)接收完成 -- 最后的通知
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 數(shù)據(jù)流寫入完畢后,關(guān)閉輸出流
[self.fileStream close];
//停止下載線程所在的runloop
CFRunLoopStop(self.downloadRunLoop);
NSLog(@"下載完成");
}
到此缘挽,使用NSURLConnection實現(xiàn)下載已經(jīng)基本實現(xiàn)瞄崇。
本篇文章旨在學(xué)習(xí)NSURLConnection的原理,如有任何疑問或?qū)懙挠袉栴}的地方壕曼,歡迎大家留言苏研,共同進(jìn)步!下載中的斷點續(xù)傳功能將在下一篇關(guān)于NSURLSession的文章中進(jìn)行詳細(xì)描述腮郊。