NSURLSession概述
NSURLSession是從iOS7開(kāi)始使用敦姻,用于替代NSURLConnection進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)傳輸?shù)念?lèi)瘾境。著名的AFNetworking庫(kù)的2.0版本采用的NSURLConnection,但是從3.0版本開(kāi)始镰惦,已經(jīng)用NSURLSession替換了NSURLConnection迷守。
NSURLSession可以與delegate(代理)綁定,在一個(gè)會(huì)話的生命周期內(nèi)旺入,delegate會(huì)被某些事件調(diào)用兑凿,例如服務(wù)端認(rèn)證或者確定加載的資源是否應(yīng)該轉(zhuǎn)化為下載。
NSURLSession實(shí)例是線程安全的茵瘾,它會(huì)創(chuàng)建NSURLSessionTask對(duì)象來(lái)執(zhí)行數(shù)據(jù)的加載礼华。被創(chuàng)建的NSURLSessionTask對(duì)象初始化狀態(tài)是suspend(掛起),需要調(diào)用resume(恢復(fù))方法來(lái)執(zhí)行拗秘。
NSURLSessionTask
NSURLSessionTask有四個(gè)子類(lèi):NSURLSessionDataTask圣絮、NSURLSessionUploadTask和NSURLSessionDownloadTask,NSURLSessionStreamTask雕旨。
- NSURLSessionDataTask用于執(zhí)行普通的任務(wù)扮匠,例如請(qǐng)求或上傳數(shù)據(jù)。
- NSURLSessionUploadTask繼承自NSURLSessionUploadTask用于上傳文件或數(shù)據(jù)到服務(wù)器凡涩。
- NSURLSessionDownloadTask會(huì)直接將響應(yīng)數(shù)據(jù)寫(xiě)入臨時(shí)文件棒搜,默認(rèn)下載到沙盒的temp目錄下。下載完成后活箕,delegate會(huì)接收到URLSession:downloadTask:didFinishDownloadingToURL: 消息力麸。
- NSURLSessionStreamTask用于建立一個(gè) TCP/IP 連接,自iOS9以后開(kāi)始使用育韩。
NSURLSessionConfiguration
NSURLSessionConfiguration是NSURLSession的配置類(lèi)克蚂,用于生成NSURLSession對(duì)象。
NSURLSessionConfiguration有三種初始化方式:
- defaultSessionConfiguration座慰。返回的全局會(huì)話使用磁盤(pán)來(lái)緩存credential, cache and cookie陨舱。
- ephemeralSessionConfiguration。返回的臨時(shí)會(huì)話使用內(nèi)存而不使用磁盤(pán)來(lái)緩存credential, cache and cookie版仔,app一旦退出,數(shù)據(jù)會(huì)被清空。
- backgroundSessionConfiguration蛮粮。返回的后臺(tái)
會(huì)話可以在app被掛起時(shí)執(zhí)行網(wǎng)絡(luò)操作益缎,但必須要傳入一個(gè)NSString類(lèi)型的identifier。
NSURLSession使用
NSURLSession提供了兩種方法來(lái)創(chuàng)建會(huì)話:
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
第二個(gè)方法可以傳入delegate來(lái)監(jiān)聽(tīng)會(huì)話事件然想,delegate需要遵循NSURLSessionDelegate協(xié)議且會(huì)被強(qiáng)引用莺奔,還可以傳入NSOperationQueue對(duì)象來(lái)指定delegate在哪個(gè)隊(duì)列被調(diào)用,傳入值為nil時(shí)变泄,session會(huì)默認(rèn)創(chuàng)建一個(gè)串行隊(duì)列來(lái)執(zhí)行delegate的方法令哟。
創(chuàng)建完會(huì)話之后,需要?jiǎng)?chuàng)建一個(gè)任務(wù)來(lái)執(zhí)行具體的網(wǎng)絡(luò)傳輸操作妨蛹。
// NSURLSessionDataTask
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;
// NSURLSessionUploadTask
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData;
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request;
// NSURLSessionDownloadTask
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request;
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url;
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;
// NSURLSessionStreamTask
- (NSURLSessionStreamTask *)streamTaskWithHostName:(NSString *)hostname port:(NSInteger)port API_AVAILABLE(macos(10.11), ios(9.0), tvos(9.0)) __WATCHOS_PROHIBITED;
- (NSURLSessionStreamTask *)streamTaskWithNetService:(NSNetService *)service API_AVAILABLE(macos(10.11), ios(9.0), tvos(9.0)) __WATCHOS_PROHIBITED;
普通任務(wù)獲取資訊列表:
// 配置URL
NSURL *url = [NSURL URLWithString:@"http://toutiao-ali.juheapi.com/toutiao/index"];
// 配置URLRequest
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setValue:@"APPCODE fd4e0a674e274e46ad3e26ab508ff21c" forHTTPHeaderField:@"Authorization"];
// 配置全局會(huì)話
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
// 返回掛起的普通任務(wù)
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 解析數(shù)據(jù)
NSString *string = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", string);
}];
// 恢復(fù)普通任務(wù)
[dataTask resume];
執(zhí)行resume方法后任務(wù)才會(huì)開(kāi)始加載數(shù)據(jù)屏富,并在回調(diào)中返回響應(yīng),不然task永遠(yuǎn)是掛起狀態(tài)蛙卤。
下載任務(wù)下載圖片資源:
// 配置URL
NSURL *url = [NSURL URLWithString:@"https://image.baidu.com/search/down?tn=download&word=download&ie=utf8&fr=detail&url=https%3A%2F%2Ftimgsa.baidu.com%2Ftimg%3Fimage%26quality%3D80%26size%3Db9999_10000%26sec%3D1530781485542%26di%3Dde29981bb7d210737be1a7da40acd236%26imgtype%3D0%26src%3Dhttp%253A%252F%252Fimg.sccnn.com%252Fbimg%252F338%252F27244.jpg&thumburl=https%3A%2F%2Fss1.bdstatic.com%2F70cFuXSh_Q1YnxGkpoWK1HF6hhy%2Fit%2Fu%3D4194403647%2C3630027324%26fm%3D27%26gp%3D0.jpg"];
// 配置全局會(huì)話
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
// 返回掛起的下載任務(wù)
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 返回沙盒tmp目錄的臨時(shí)文件
NSLog(@"%@", location);
}];
// 恢復(fù)下載任務(wù)
[downloadTask resume];
通過(guò)代理方法實(shí)現(xiàn)數(shù)據(jù)加載
// 配置URL
NSURL *url = [NSURL URLWithString:@"https://image.baidu.com/search/down?tn=download&word=download&ie=utf8&fr=detail&url=https%3A%2F%2Ftimgsa.baidu.com%2Ftimg%3Fimage%26quality%3D80%26size%3Db9999_10000%26sec%3D1530781485542%26di%3Dde29981bb7d210737be1a7da40acd236%26imgtype%3D0%26src%3Dhttp%253A%252F%252Fimg.sccnn.com%252Fbimg%252F338%252F27244.jpg&thumburl=https%3A%2F%2Fss1.bdstatic.com%2F70cFuXSh_Q1YnxGkpoWK1HF6hhy%2Fit%2Fu%3D4194403647%2C3630027324%26fm%3D27%26gp%3D0.jpg"];
// 配置全局會(huì)話
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
// 傳入代理對(duì)象
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
// 返回掛起的普通任務(wù)狠半,不用completionHandler返回?cái)?shù)據(jù)
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url];
// 恢復(fù)下載任務(wù)
[dataTask resume];
會(huì)話初始化時(shí)將self作為代理對(duì)象傳入,代理對(duì)象需要遵循NSURLSessionDataDelegate協(xié)議和NSURLSessionTaskDelegate協(xié)議颤难,任務(wù)在執(zhí)行過(guò)程中通知代理對(duì)象具體的執(zhí)行步驟神年。
#pragma mark NSURLSessionDataDelegate
/**
任務(wù)收到服務(wù)器的初始響應(yīng)
@param session 用戶創(chuàng)建的會(huì)話
@param dataTask 用戶創(chuàng)建的數(shù)據(jù)任務(wù)
@param response 服務(wù)器響應(yīng)
@param completionHandler 回調(diào),告知系統(tǒng)是否繼續(xù)傳輸
*/
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
// 是否允許繼續(xù)傳輸數(shù)據(jù)
NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
// 響應(yīng)內(nèi)容的預(yù)期長(zhǎng)度行嗤,若預(yù)期長(zhǎng)度未知已日,返回-1
NSInteger expected = (NSInteger)response.expectedContentLength;
expected = expected > 0 ? expected : 0;
// 不執(zhí)行此行代碼,默認(rèn)取消傳輸
completionHandler(disposition);
}
/**
任務(wù)收到服務(wù)器返回的數(shù)據(jù)(可能多次調(diào)用)
@param session 用戶創(chuàng)建的會(huì)話
@param dataTask 用戶創(chuàng)建的數(shù)據(jù)任務(wù)
@param data 當(dāng)次返回的數(shù)據(jù)
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
if (!self.jjData) {
self.jjData = [[NSMutableData alloc] init];
}
// 拼接當(dāng)次返回的數(shù)據(jù)
[self.jjData appendData:data];
// 計(jì)算當(dāng)前總數(shù)據(jù)長(zhǎng)度
const NSInteger totalSize = self.jjData.length;
NSLog(@"當(dāng)前數(shù)據(jù)大姓て痢:%ld", totalSize);
}
#pragma mark NSURLSessionTaskDelegate
/**
任務(wù)完成數(shù)據(jù)傳輸
@param session 用戶創(chuàng)建的會(huì)話
@param task 用戶創(chuàng)建的任務(wù)
@param error 錯(cuò)誤信息
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (nil == error) {
NSLog(@"總數(shù)據(jù)大形娴小:%ld", self.jjData.length);
}
}
假如需要實(shí)時(shí)顯示加載進(jìn)度,在
URLSession:dataTask:didReceiveResponse:responsecompletionHandler:方法中獲取響應(yīng)內(nèi)容的預(yù)期大小既琴,在URLSession:dataTask:didReceiveData:方法的中獲取當(dāng)前數(shù)據(jù)的大小占婉,最后在URLSession:task:didCompleteWithError:方法中關(guān)閉加載進(jìn)度。
除了resmue方法甫恩,URLSessionTask還提供了暫停和取消的方法逆济。
// 暫停任務(wù)
- (void)suspend;
// 取消任務(wù)
- (void)cancel;
總結(jié)
學(xué)習(xí)NSURLSession的目的是為了之后學(xué)習(xí)SDWebImage的Downloader模塊,Downloader是SDWebimage的核心模塊磺箕,包含了兩大類(lèi)SDWebImageDownloader和SDWebImageDownloaderOperation奖慌。在學(xué)習(xí)SDWebImageDownloaderOperation時(shí),會(huì)對(duì)NSURLSession的應(yīng)用做進(jìn)一步的闡述松靡。
AFNetworking庫(kù)也是基于NSURLSession封裝的简僧,等學(xué)習(xí)完SDWebImage的源碼,筆者會(huì)研究AFNetworking的源碼雕欺,希望今天的學(xué)習(xí)能起到一些幫助作用岛马。