簡介
NSURLSession
是蘋果公司在2013的 WWDC大會上隨 iOS7 一起發(fā)布的,是 NSURLConnection
的繼任者摘悴。 NSURLConnection
在iOS9 之后也被宣布棄用馋嗜。目前 AFNetworking满力、SDWebImage
等知名類庫也都更新使用了 NSURLSession 作喘。
NSURLSession的優(yōu)勢:
- 針對不同的網(wǎng)絡(luò)請求任務(wù)提供了專門的解決方案厢蒜;
- 支持任務(wù)取消霞势、暫停、恢復(fù)斑鸦、支持應(yīng)用程序后臺下載愕贡;
- 安全身份驗(yàn)證方案;
- 下載操作內(nèi)存優(yōu)化巷屿;
- 更靈活請求的配置固以。
使用
首先我們看下NSURLSession最簡單的使用,通過下面代碼就可以實(shí)現(xiàn)了基本的網(wǎng)絡(luò)請求了嘱巾。
NSURL *url = [NSURL URLWithString:@"http://....."];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// handle response
}];
[task resume];
所有的NSURLSession 網(wǎng)絡(luò)請求基本遵循以下幾個步驟:
- 獲取NSURLSession對象
- 通過session對象創(chuàng)建 task 任務(wù)
- 執(zhí)行 task(task 默認(rèn)是掛起的憨琳,通過resume執(zhí)行)
NSURLSession
NSURLSession
繼承NSObject
,提供了3種會話模式旬昭,主要通過 NSURLSessionConfiguration
來進(jìn)行初始化篙螟,同時還可以設(shè)置 dalegate
來進(jìn)行下載過程監(jiān)聽
+ (NSURLSession *)sharedSession; //共享的會話,該會話使用全局的Cache问拘,Cookie和證書,無法進(jìn)行 Configuration配置
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration; // 通過 NSURLSessionConfiguration初始化
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue; // 通過 NSURLSessionConfiguration遍略、 delegate 、隊(duì)列初始化
接下來我們看下NSURLSessionConfiguration的3種配置骤坐,他們是和NSURLSession的會話模式一一對應(yīng)的
@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));
-
defaultSessionConfiguration
默認(rèn)配置使用的是持久化的硬盤緩存墅冷,存儲證書到用戶鑰匙鏈。存儲cookie到shareCookie或油。 -
ephemeralSessionConfiguration
這個配置中不會對緩存寞忿,Cookie 和證書進(jìn)行持久性的存儲。 -
+ backgroundSessionConfigurationWithIdentifier:(NSString *)identifier
它會返回一個后臺 session顶岸∏徽茫可以在應(yīng)用程序掛起,退出或者崩潰的情況下運(yùn)行上傳和下載任務(wù)辖佣。
另外: NSURLSessionConfiguration是提供了很多屬性霹抛,從 指定可用網(wǎng)絡(luò),到 cookie卷谈,安全性杯拐,緩存策略,再到使用自定義協(xié)議,啟動事件的設(shè)置端逼,以及用于移動設(shè)備優(yōu)化的幾個新屬性朗兵,可以找到幾乎任何你想要進(jìn)行配置的選項(xiàng)。
了解了 NSURLSession
的模式以及配置顶滩,接下來我們看一下 NSURLSessionTask
NSURLSessionTask
NSURLsessionTask
是一個抽象類余掖,其下有 3 個實(shí)體子類可以直使用用:NSURLSessionDataTask
、NSURLSessionUploadTask
礁鲁、NSURLSessionDownloadTask
盐欺。這 3 個子類封裝了程序三個最基本的網(wǎng)絡(luò)任務(wù):獲取數(shù)據(jù),比如 JSON 或者 XML仅醇,上傳文件和下載文件冗美。
-
NSURLSessionDataTask
可以用來處理一般的網(wǎng)絡(luò)請求 -
NSURLSessionDownloadTask
主要用于處理下載請求。 -
NSURLSessionUploadTask
用于處理上傳請求析二。
當(dāng)一個 NSURLSessionDataTask
完成時粉洼,它會帶有相關(guān)聯(lián)的數(shù)據(jù),而一個 NSURLSessionDownloadTask
任務(wù)結(jié)束時甲抖,它會帶回已下載文件的一個臨時的文件路徑。因?yàn)橐话銇碚f心铃,服務(wù)端對于一個上傳任務(wù)的響應(yīng)也會有相關(guān)數(shù)據(jù)返回准谚,所以 NSURLSessionUploadTask
繼承自 NSURLSessionDataTask
。
所有的task
都是可以取消去扣,暫椭危或者恢復(fù)的。當(dāng)一個 download task
取消時愉棱,可以通過選項(xiàng)來創(chuàng)建一個恢復(fù)數(shù)據(jù)(resume data)唆铐,然后可以傳遞給下一次新創(chuàng)建的 download task,以便繼續(xù)之前的下載奔滑。
不同于直接使用alloc-init
初始化方法艾岂,task
是由一個 NSURLSession
創(chuàng)建的。每個 task 的構(gòu)造方法都對應(yīng)有或者沒有 completionHandler
block 的兩個版本朋其。如果 使用completionHandler
block王浴,代理回調(diào)將不會執(zhí)行。
NSURLSessionTask工廠方法
NSURLSessionTask
的工廠方法可以根據(jù)我們不同的需求返回不同的 task
梅猿,這些task
不會立即運(yùn)行氓辣,允許我們進(jìn)一步的配置,然后可以使用 resume
方法來讓它開始運(yùn)行袱蚓。
Datatask
可以通過 NSURL
或 NSURLRequest
創(chuàng)建
NSURL *URL = [NSURL URLWithString:@"http://example.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// ...
}];
[task resume];
Uploadtask
的創(chuàng)建需要使用一個 request
钞啸,另外加上一個要上傳的 NSData 對象
或者是一個本地文件的路徑對應(yīng)的 NSURL:
NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSData *data = ...;
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
fromData:data
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// ...
}];
[uploadTask resume];
Download task
也需要一個 request或者Url,不同之處在于 completionHandler
這個 block。Datatask
和 uploadtask
會在任務(wù)完成時一次性返回体斩,但是 Download task
是將數(shù)據(jù)一點(diǎn)點(diǎn)地寫入本地的臨時文件梭稚。所以在 completionHandler 這個 block 里,我們需要把文件從一個臨時地址移動到一個永久的地址保存起來:
NSURL *URL = [NSURL URLWithString:@"http://example.com/file.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request
completionHandler: ^(NSURL *location, NSURLResponse *response, NSError *error) {
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSURL *documentsDirectoryURL = [NSURL fileURLWithPath:documentsPath];
NSURL *newFileLocation = [documentsDirectoryURL URLByAppendingPathComponent:[[response URL] lastPathComponent]];
[[NSFileManager defaultManager] copyItemAtURL:location toURL:newFileLocation error:nil];
}];
[downloadTask resume];
上面介紹了幾種 NSURLSessionTask 的基本使用硕勿,都是通過completionHandler
這個 block 來進(jìn)行任務(wù)處理回調(diào)的哨毁,下來我們看看他的代理都有哪些,以及使用
NSURLSession代理
在我們請求過程中源武,如果想要監(jiān)聽網(wǎng)絡(luò)操作過程中發(fā)生的事件扼褪,比如我們下載一個大文件的時候,如果要等到下載完成可能會需要比較長的事件粱栖,這時候更好的體驗(yàn)是能夠提供一個下載進(jìn)度话浇。類似這樣的事件我們就需要用到代理。
我們在使用三種 task 的任意一種的時候都可以指定相應(yīng)的代理闹究。NSURLSession 的代理對象結(jié)構(gòu)如下:
-
NSURLSessionDelegate
作為所有代理的基類幔崖,定義了網(wǎng)絡(luò)請求最基礎(chǔ)的代理方法。 -
NSURLSessionTaskDelegate
- 定義了網(wǎng)絡(luò)請求任務(wù)相關(guān)的代理方法渣淤。 -
NSURLSessionDownloadDelegate
- 用于下載任務(wù)相關(guān)的代理方法赏寇,比如下載進(jìn)度等等。 -
NSURLSessionDataDelegate
- 用于普通數(shù)據(jù)任務(wù)和上傳任務(wù)价认。
下面以下載為例嗅定,我們看下代碼如何實(shí)現(xiàn)的
- (void)downloadtask{
// 服務(wù)器地址
NSURL *url = [NSURL URLWithString:@"http://d1.music.126.net/dmusic/NeteaseMusic_1.5.10_632_web.dmg"];
// 創(chuàng)建 SessionConfiguration配置
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
// 創(chuàng)建session實(shí)例并設(shè)置代理,用于監(jiān)聽下載
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
// 創(chuàng)建 task
self.task = [session downloadTaskWithURL:url];
// 開始執(zhí)行
[self.task resume];
}
#pragma -mark NSURLSessionDownloadDelegate
/* 當(dāng)下載任務(wù)完成下載時調(diào)用*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location{
// location是一個temp文件下的臨時路徑,自己需要保存
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
}
/* 定期發(fā)送通知委托下載進(jìn)度. */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
// 可在這里通過已寫入的長度和總長度算出下載進(jìn)度
CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
NSLog(@"%f",progress);
}
/* 當(dāng)下載已恢復(fù)時發(fā)送 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{
}
/* 任務(wù)完成調(diào)用,查看是否成功 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
if (!error){
NSLog(@"下載完成");
}else{
NSLog(@"下載失敗");
}
}
通過實(shí)現(xiàn)NSURLSessionDownloadDelegate 協(xié)議,就可以實(shí)現(xiàn)接收下載完成的通知用踩,下載進(jìn)度變化的通知渠退,以及下載進(jìn)度恢復(fù)的通知。
總結(jié)
NSURLSession
除了我們介紹的支持 task 特性脐彩,NSURLSessionConfiguration 配置對象碎乃,以及代理之外還提供了很多關(guān)于網(wǎng)絡(luò)請求的相關(guān)特性,比如緩存控制惠奸,Cookie 控制梅誓,HTTP 驗(yàn)證操作等等》鹉希總之 NSURLSession 簡單的接口之外证九,也提供了強(qiáng)大的體系。
NSURLSession
相比 AFN
這些第三方庫來說也有一些不足共虑,比如它沒有提供很方便的自動數(shù)據(jù)類型轉(zhuǎn)換愧怜。比如,AFN 中可以自動將服務(wù)端返回的 JSON 數(shù)據(jù)識別并解析出來妈拌,而使用 NSURLSession
則需要自己來完成拥坛。
后續(xù)有時間我會繼續(xù)分析一下 NSURLSession在 AFN 中的使用蓬蝶!
參考鏈接:
https://developer.apple.com/documentation/foundation/nsurlsession
https://swiftcafe.io/2015/12/20/nsurlsession
http://www.cocoachina.com/ios/20180108/21778.html