iOS網(wǎng)絡(luò)編程--文件下載

使用NSURLConnection實(shí)現(xiàn)下載

1. 小文件下載

  1. 第一種方式(NSData)
//使用NSDta直接加載網(wǎng)絡(luò)上的url資源(不考慮線(xiàn)程) 
-(void)dataDownload { 
//1.確定資源路徑 
NSURL *url = [NSURL URLWithString:@"http://tupian.qqjay.com/u/2013/1127/19_222949_14.jpg"]; 
//2.根據(jù)URL加載對(duì)應(yīng)的資源 
NSData *data = [NSData dataWithContentsOfURL:url]; 
//3.轉(zhuǎn)換并顯示數(shù)據(jù) 
UIImage *image = [UIImage imageWithData:data]; 
self.imageView.image = image; 
}
  1. 第二種方式(NSURLConnection-sendAsync)
//使用NSURLConnection發(fā)送異步請(qǐng)求下載文件資源 
-(void)connectDownload { 
//1.確定請(qǐng)求路徑 
NSURL *url = [NSURL URLWithString:@"http://tupian.qqjay.com/u/2013/1127/19_222949_14.jpg"]; 
//2.創(chuàng)建請(qǐng)求對(duì)象 
NSURLRequest *request = [NSURLRequest requestWithURL:url]; 
//3.使用NSURLConnection發(fā)送一個(gè)異步請(qǐng)求 
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { 
//4.拿到并處理數(shù)據(jù) 
UIImage *image = [UIImage imageWithData:data]; 
self.imageView.image = image; 
}]; 
}
  1. 第三種方式(NSURLConnection-delegate)
//使用NSURLConnection設(shè)置代理發(fā)送異步請(qǐng)求的方式下載文件 
-(void)connectionDelegateDownload { 
//1.確定請(qǐng)求路徑 
NSURL *url = [NSURL URLWithString:@"下載文件的URL地址"]; 
//2.創(chuàng)建請(qǐng)求對(duì)象 
NSURLRequest *request = [NSURLRequest requestWithURL:url]; 
//3.使用NSURLConnection設(shè)置代理并發(fā)送異步請(qǐng)求 
[NSURLConnection connectionWithRequest:request delegate:self]; 
}
pragma mark--NSURLConnectionDataDelegate
//當(dāng)接收到服務(wù)器響應(yīng)的時(shí)候調(diào)用,該方法只會(huì)調(diào)用一次
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    //創(chuàng)建一個(gè)容器,用來(lái)接收服務(wù)器返回的數(shù)據(jù)
    self.fileData = [NSMutableData data];
    //獲得當(dāng)前要下載文件的總大小(通過(guò)響應(yīng)頭得到)
    NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
    self.totalLength = res.expectedContentLength;
    NSLog(@"%zd",self.totalLength);
    //拿到服務(wù)器端推薦的文件名稱(chēng)
    self.fileName = res.suggestedFilename;
}
//當(dāng)接收到服務(wù)器返回的數(shù)據(jù)時(shí)會(huì)調(diào)用
//該方法可能會(huì)被調(diào)用多次
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//    NSLog(@"%s",__func__);
    //拼接每次下載的數(shù)據(jù)
    [self.fileData appendData:data];
    //計(jì)算當(dāng)前下載進(jìn)度并刷新UI顯示
    self.currentLength = self.fileData.length;
    NSLog(@"%f",1.0* self.currentLength/self.totalLength);
    self.progressView.progress = 1.0* self.currentLength/self.totalLength;
}
//當(dāng)網(wǎng)絡(luò)請(qǐng)求結(jié)束之后調(diào)用
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    //文件下載完畢把接受到的文件數(shù)據(jù)寫(xiě)入到沙盒中保存
    //1.確定要保存文件的全路徑
    //caches文件夾路徑
    NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *fullPath = [caches stringByAppendingPathComponent:self.fileName];
    //2.寫(xiě)數(shù)據(jù)到文件中
    [self.fileData writeToFile:fullPath atomically:YES];
    NSLog(@"%@",fullPath);
}
//當(dāng)請(qǐng)求失敗的時(shí)候調(diào)用該方法
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"%s",__func__);
}

2. 大文件下載

  1. 實(shí)現(xiàn)思路
    邊接收數(shù)據(jù)邊寫(xiě)文件以解決內(nèi)存越來(lái)越大的問(wèn)題
  2. 核心代碼
//當(dāng)接收到服務(wù)器響應(yīng)的時(shí)候調(diào)用,該方法只會(huì)調(diào)用一次 
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 
//0.獲得當(dāng)前要下載文件的總大小(通過(guò)響應(yīng)頭得到) 
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response; 
self.totalLength = res.expectedContentLength; 
NSLog(@"%zd",self.totalLength); 
//創(chuàng)建一個(gè)新的文件,用來(lái)當(dāng)接收到服務(wù)器返回?cái)?shù)據(jù)的時(shí)候往該文件中寫(xiě)入數(shù)據(jù) //1.獲取文件管理者 
NSFileManager *manager = [NSFileManager defaultManager]; 
//2.拼接文件的全路徑 
//caches文件夾路徑 
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 
NSString *fullPath = [caches stringByAppendingPathComponent:res.suggestedFilename]; 
self.fullPath = fullPath; 
//3.創(chuàng)建一個(gè)空的文件 
[manager createFileAtPath:fullPath contents:nil attributes:nil]; 
} 
//當(dāng)接收到服務(wù)器返回的數(shù)據(jù)時(shí)會(huì)調(diào)用 
//該方法可能會(huì)被調(diào)用多次 
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 
//1.創(chuàng)建一個(gè)用來(lái)向文件中寫(xiě)數(shù)據(jù)的文件句柄 
//注意當(dāng)下載完成之后,該文件句柄需要關(guān)閉,調(diào)用closeFile方法 
NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath]; 
//2.設(shè)置寫(xiě)數(shù)據(jù)的位置(追加) 
[handle seekToEndOfFile]; 
//3.寫(xiě)數(shù)據(jù) [handle writeData:data]; 
//4.計(jì)算當(dāng)前文件的下載進(jìn)度 
self.currentLength += data.length; 
NSLog(@"%f",1.0* self.currentLength/self.totalLength); 
self.progressView.progress = 1.0* self.currentLength/self.totalLength;
}

3. 大文件斷點(diǎn)續(xù)傳

  1. 實(shí)現(xiàn)思路
    在下載文件的時(shí)候不再是整塊的從頭開(kāi)始下載,而是看當(dāng)前文件已經(jīng)下載到哪個(gè)地方,然后從該地方接著往后面下載。可以通過(guò)在請(qǐng)求對(duì)象中設(shè)置請(qǐng)求頭實(shí)現(xiàn)。
  2. 解決方案(設(shè)置請(qǐng)求頭)
//2.創(chuàng)建請(qǐng)求對(duì)象 
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 
//2.1 設(shè)置下載文件的某一部分 
// 只要設(shè)置HTTP請(qǐng)求頭的Range屬性, 就可以實(shí)現(xiàn)從指定位置開(kāi)始下載 
/* 
表示頭500個(gè)字節(jié):Range: bytes=0-499 
表示第二個(gè)500字節(jié):Range: bytes=500-999 
表示最后500個(gè)字節(jié):Range: bytes=-500 
表示500字節(jié)以后的范圍:Range: bytes=500- 
*/ 
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentLength]; 
[request setValue:range forHTTPHeaderField:@"Range"];
  1. 注意點(diǎn)(下載進(jìn)度并判斷是否需要重新創(chuàng)建文件)
//獲得當(dāng)前要下載文件的總大小(通過(guò)響應(yīng)頭得到) 
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response; 
//注意點(diǎn):res.expectedContentLength獲得是本次請(qǐng)求要下載的文件的大小(并非是完整的文件的大小) 
//因此:文件的總大小 == 本次要下載的文件大小+已經(jīng)下載的文件的大小 
self.totalLength = res.expectedContentLength + self.currentLength; 
NSLog(@"----------------------------%zd",self.totalLength); 
//0 判斷當(dāng)前是否已經(jīng)下載過(guò),如果當(dāng)前文件已經(jīng)存在,那么直接返回
 if (self.currentLength >0) { return; }
  1. 輸出流

  2. 使用輸出流也可以實(shí)現(xiàn)和NSFileHandle相同的功能

  3. 如何使用

//1.創(chuàng)建一個(gè)數(shù)據(jù)輸出流
/*
第一個(gè)參數(shù):二進(jìn)制的流數(shù)據(jù)要寫(xiě)入到哪里
第二個(gè)參數(shù):采用什么樣的方式寫(xiě)入流數(shù)據(jù),如果YES則表示追加,如果是NO則表示覆蓋
*/
NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:fullPath append:YES];
//只要調(diào)用了該方法就會(huì)往文件中寫(xiě)數(shù)據(jù)
//如果文件不存在,那么會(huì)自動(dòng)的創(chuàng)建一個(gè)
[stream open];
self.stream = stream;
//2.當(dāng)接收到數(shù)據(jù)的時(shí)候?qū)憯?shù)據(jù)
//使用輸出流寫(xiě)數(shù)據(jù)
/*
第一個(gè)參數(shù):要寫(xiě)入的二進(jìn)制數(shù)據(jù)
第二個(gè)參數(shù):要寫(xiě)入的數(shù)據(jù)的大小
*/
[self.stream write:data.bytes maxLength:data.length];
//3.當(dāng)文件下載完畢的時(shí)候關(guān)閉輸出流
//關(guān)閉輸出流
[self.stream close];
self.stream = nil;
  1. 使用多線(xiàn)程下載文件的思路
  • 01 開(kāi)啟多條線(xiàn)程,每條線(xiàn)程都只下載文件的一部分(通過(guò)設(shè)置請(qǐng)求頭中的Range來(lái)實(shí)現(xiàn))
  • 02 創(chuàng)建一個(gè)和需要下載文件大小一致的文件,判斷當(dāng)前是那個(gè)線(xiàn)程,根據(jù)當(dāng)前的線(xiàn)程來(lái)判斷下載的數(shù)據(jù)應(yīng)該寫(xiě)入到文件中的哪個(gè)位置。(假設(shè)開(kāi)5條線(xiàn)程來(lái)下載10M的文件,那么線(xiàn)程1下載0-2M,線(xiàn)程2下載2-4M一次類(lèi)推,當(dāng)接收到服務(wù)器返回的數(shù)據(jù)之后應(yīng)該先判斷當(dāng)前線(xiàn)程是哪個(gè)線(xiàn)程,假如當(dāng)前線(xiàn)程是線(xiàn)程2,那么在寫(xiě)數(shù)據(jù)的時(shí)候就從文件的2M位置開(kāi)始寫(xiě)入)
  • 03 代碼相關(guān):使用NSFileHandle這個(gè)類(lèi)的seekToFileOfSet方法,來(lái)向文件中特定的位置寫(xiě)入數(shù)據(jù)。
  • 04 技術(shù)相關(guān)
    a.每個(gè)線(xiàn)程通過(guò)設(shè)置請(qǐng)求頭下載文件中的某一個(gè)部分
    b.通過(guò)NSFileHandle向文件中的指定位置寫(xiě)數(shù)據(jù)

使用NSURLSession實(shí)現(xiàn)下載

1. NSURLSession下載文件-代理

  1. 創(chuàng)建NSURLSession對(duì)象,設(shè)置代理(默認(rèn)配置)
//1.創(chuàng)建NSURLSession,并設(shè)置代理 
/* 
第一個(gè)參數(shù):session對(duì)象的全局配置設(shè)置,一般使用默認(rèn)配置就可以 
第二個(gè)參數(shù):誰(shuí)成為session對(duì)象的代理 
第三個(gè)參數(shù):代理方法在哪個(gè)隊(duì)列中執(zhí)行(在哪個(gè)線(xiàn)程中調(diào)用),如果是主隊(duì)列那么在主線(xiàn)程中執(zhí)行,如果是非主隊(duì)列,那么在子線(xiàn)程中執(zhí)行 
*/ 
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
  1. 根據(jù)Session對(duì)象創(chuàng)建一個(gè)NSURLSessionDataTask任務(wù)(post和get選擇)
//創(chuàng)建task
NSURL *url = [NSURL URLWithString:@"http://tupian.qqjay.com/u/2013/1127/19_222949_14.jpg"];
//注意:如果要發(fā)送POST請(qǐng)求,那么請(qǐng)使用dataTaskWithRequest,設(shè)置一些請(qǐng)求頭信息
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url];
  1. 執(zhí)行任務(wù)(其它方法,如暫停、取消等)
//啟動(dòng)task
//[dataTask resume];
//其它方法,如取消任務(wù),暫停任務(wù)等
//[dataTask cancel];
//[dataTask suspend];
```
4. 遵守代理協(xié)議,實(shí)現(xiàn)代理方法(3個(gè)相關(guān)的代理方法)
```
/* 
1.當(dāng)接收到服務(wù)器響應(yīng)的時(shí)候調(diào)用 
session:發(fā)送請(qǐng)求的session對(duì)象 
dataTask:根據(jù)NSURLSession創(chuàng)建的task任務(wù) 
response:服務(wù)器響應(yīng)信息(響應(yīng)頭) 
completionHandler:通過(guò)該block回調(diào),告訴服務(wù)器端是否接收返回的數(shù)據(jù) 
*/
-(void)URLSession:(nonnull NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveResponse:(nonnull NSURLResponse *)response completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler
/*
2.當(dāng)接收到服務(wù)器返回的數(shù)據(jù)時(shí)調(diào)用 該方法可能會(huì)被調(diào)用多次 
*/
-(void)URLSession:(nonnull NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveData:(nonnull NSData *)data
/* 
3.當(dāng)請(qǐng)求完成之后調(diào)用該方法 不論是請(qǐng)求成功還是請(qǐng)求失敗都調(diào)用該方法,如果請(qǐng)求失敗,那么error對(duì)象有值,否則那么error對(duì)象為空 
*/
-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error
```
5. 當(dāng)接收到服務(wù)器響應(yīng)的時(shí)候,告訴服務(wù)器接收數(shù)據(jù)(調(diào)用block)
```
//默認(rèn)情況下,當(dāng)接收到服務(wù)器響應(yīng)之后,服務(wù)器認(rèn)為客戶(hù)端不需要接收數(shù)據(jù),所以后面的代理方法不會(huì)調(diào)用 
//如果需要繼續(xù)接收服務(wù)器返回的數(shù)據(jù),那么需要調(diào)用block,并傳入對(duì)應(yīng)的策略 
/* 
NSURLSessionResponseCancel = 0, 取消任務(wù) 
NSURLSessionResponseAllow = 1, 接收任務(wù) 
NSURLSessionResponseBecomeDownload = 2, 轉(zhuǎn)變成下載 
NSURLSessionResponseBecomeStream NS_ENUM_AVAILABLE(10_11, 9_0) = 3, 轉(zhuǎn)變成流 
*/ 
completionHandler(NSURLSessionResponseAllow);
```

###2. NSURLSessionDownloadTask實(shí)現(xiàn)大文件下載
1. 使用NSURLSession和NSURLSessionDownload可以很方便的實(shí)現(xiàn)文件下載操作
```
/*
    第一個(gè)參數(shù):要下載文件的url路徑
    第二個(gè)參數(shù):當(dāng)接收完服務(wù)器返回的數(shù)據(jù)之后調(diào)用該block
    location:下載的文件的保存地址(默認(rèn)是存儲(chǔ)在沙盒中tmp文件夾下面,隨時(shí)會(huì)被刪除)
    response:服務(wù)器響應(yīng)信息,響應(yīng)頭
    error:該請(qǐng)求的錯(cuò)誤信息
    */
    //說(shuō)明:downloadTaskWithURL方法已經(jīng)實(shí)現(xiàn)了在下載文件數(shù)據(jù)的過(guò)程中邊下載文件數(shù)據(jù),邊寫(xiě)入到沙盒文件的操作
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * __nullable location, NSURLResponse * __nullable response, NSError * __nullable error)
```
2. downloadTaskWithURL內(nèi)部默認(rèn)已經(jīng)實(shí)現(xiàn)了變下載邊寫(xiě)入操作,所以不用開(kāi)發(fā)人員擔(dān)心內(nèi)存問(wèn)題
3. 文件下載后默認(rèn)保存在tmp文件目錄,需要開(kāi)發(fā)人員手動(dòng)的剪切到合適的沙盒目錄
4. 缺點(diǎn):沒(méi)有辦法監(jiān)控下載進(jìn)度

###3. 使用NSURLSessionDownloadTask實(shí)現(xiàn)大文件下載-監(jiān)聽(tīng)下載進(jìn)度
1. 創(chuàng)建NSURLSession并設(shè)置代理,通過(guò)NSURLSessionDownloadTask并以代理的方式來(lái)完成大文件的下載
```
//1.創(chuàng)建NSULRSession,設(shè)置代理
self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//2.創(chuàng)建task
NSURL *url = [NSURL URLWithString:@"URL字符串"];
self.downloadTask = [self.session downloadTaskWithURL:url];
//3.執(zhí)行task
[self.downloadTask resume];
```
2. 常用代理方法的說(shuō)明
```
/* 
1.當(dāng)接收到下載數(shù)據(jù)的時(shí)候調(diào)用,可以在該方法中監(jiān)聽(tīng)文件下載的進(jìn)度 
該方法會(huì)被調(diào)用多次 
totalBytesWritten:已經(jīng)寫(xiě)入到文件中的數(shù)據(jù)大小 
totalBytesExpectedToWrite:目前文件的總大小 
bytesWritten:本次下載的文件數(shù)據(jù)大小 
*/
-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
/* 
2.恢復(fù)下載的時(shí)候調(diào)用該方法 
fileOffset:恢復(fù)之后,要從文件的什么地方開(kāi)發(fā)下載 
expectedTotalBytes:該文件數(shù)據(jù)的總大小 
*/
-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
/* 
3.下載完成之后調(diào)用該方法 
*/
-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location
/* 
4.請(qǐng)求完成之后調(diào)用 
如果請(qǐng)求失敗,那么error有值 
*/
-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error
```
3. 實(shí)現(xiàn)斷點(diǎn)下載相關(guān)代碼
```
//如果任務(wù),取消了那么以后就不能恢復(fù)了
// [self.downloadTask cancel];
//如果采取這種方式來(lái)取消任務(wù),那么該方法會(huì)通過(guò)resumeData保存當(dāng)前文件的下載信息
//只要有了這份信息,以后就可以通過(guò)這些信息來(lái)恢復(fù)下載
[self.downloadTask cancelByProducingResumeData:^(NSData * __nullable resumeData) { self.resumeData = resumeData;}];
//繼續(xù)下載
//首先通過(guò)之前保存的resumeData信息,創(chuàng)建一個(gè)下載任務(wù)
self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData]; 
[self.downloadTask resume];
```
4. 計(jì)算當(dāng)前下載進(jìn)度
```
//獲取文件下載進(jìn)度
self.progress.progress = 1.0 * totalBytesWritten/totalBytesExpectedToWrite;
```
5. 局限性
  - 如果用戶(hù)點(diǎn)擊暫停之后退出程序,那么需要把恢復(fù)下載的數(shù)據(jù)寫(xiě)一份到沙盒,代碼復(fù)雜度更高
  - 如果用戶(hù)在下載中途未保存恢復(fù)下載數(shù)據(jù)即退出程序,則不具備可操作性

###4. 使用NSURLSessionDataTask實(shí)現(xiàn)大文件離線(xiàn)斷點(diǎn)下載(完整)

1. 關(guān)于NSOutputStream的使用
```
//1. 創(chuàng)建一個(gè)輸入流,數(shù)據(jù)追加到文件的屁股上
//把數(shù)據(jù)寫(xiě)入到指定的文件地址,如果當(dāng)前文件不存在,則會(huì)自動(dòng)創(chuàng)建
NSOutputStream *stream = [[NSOutputStream alloc]initWithURL:[NSURL fileURLWithPath:[self fullPath]] append:YES];
//2. 打開(kāi)流
[stream open];
//3. 寫(xiě)入流數(shù)據(jù)
[stream write:data.bytes maxLength:data.length];
//4.當(dāng)不需要的時(shí)候應(yīng)該關(guān)閉流
[stream close];
```
2. 關(guān)于網(wǎng)絡(luò)請(qǐng)求請(qǐng)求頭的設(shè)置(可以設(shè)置請(qǐng)求下載文件的某一部分)
```
//1. 設(shè)置請(qǐng)求對(duì)象
//1.1 創(chuàng)建請(qǐng)求路徑
NSURL *url = [NSURL URLWithString:@"URL字符串"];
//1.2 創(chuàng)建可變請(qǐng)求對(duì)象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//1.3 拿到當(dāng)前文件的殘留數(shù)據(jù)大小
self.currentContentLength = [self FileSize];
//1.4 告訴服務(wù)器從哪個(gè)地方開(kāi)始下載文件數(shù)據(jù)
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentContentLength];
NSLog(@"%@",range);
//1.5 設(shè)置請(qǐng)求頭
[request setValue:range forHTTPHeaderField:@"Range"];
```
3. NSURLSession對(duì)象的釋放
```
-(void)dealloc{ 
//在最后的時(shí)候應(yīng)該把session釋放,以免造成內(nèi)存泄露 
// NSURLSession設(shè)置過(guò)代理后,需要在最后(比如控制器銷(xiāo)毀的時(shí)候)調(diào)用session的invalidateAndCancel或者resetWithCompletionHandler,才不會(huì)有內(nèi)存泄露 
// [self.session invalidateAndCancel];
 [self.session resetWithCompletionHandler:^{ NSLog(@"釋放---");
 }];
}
```
4. 優(yōu)化部分
  - 關(guān)于文件下載進(jìn)度的實(shí)時(shí)更新
  - 方法的獨(dú)立與抽取



















最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,283評(píng)論 6 530
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 97,947評(píng)論 3 413
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,094評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,485評(píng)論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,268評(píng)論 6 405
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,817評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,906評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,039評(píng)論 0 285
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,551評(píng)論 1 331
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,502評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,662評(píng)論 1 366
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,188評(píng)論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,907評(píng)論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,304評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,563評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,255評(píng)論 3 389
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,637評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容

  • NSURLSession 使用步驟使用NSURLSession對(duì)象創(chuàng)建Task,然后執(zhí)行Task -(void)g...
    BEYOND黃閱讀 922評(píng)論 0 0
  • iOS開(kāi)發(fā)系列--網(wǎng)絡(luò)開(kāi)發(fā) 概覽 大部分應(yīng)用程序都或多或少會(huì)牽扯到網(wǎng)絡(luò)開(kāi)發(fā),例如說(shuō)新浪微博、微信等,這些應(yīng)用本身可...
    lichengjin閱讀 3,694評(píng)論 2 7
  • 在蘋(píng)果徹底棄用NSURLConnection之后自己總結(jié)的一個(gè)網(wǎng)上的內(nèi)容,加上自己寫(xiě)的小Demo,很多都是借鑒網(wǎng)絡(luò)...
    付寒宇閱讀 4,300評(píng)論 2 13
  • 218.241.181.202 wxhl60 123456 192.168.10.253 wxhl66 wxhl6...
    CYC666閱讀 1,407評(píng)論 0 6
  • URLSessionNSURLSession是iOS7中新的網(wǎng)絡(luò)接口,與NSURLConnection是并列的。當(dāng)...
    醉葉惜秋閱讀 1,321評(píng)論 0 0