NSURLSession概述
NSURLSession是從iOS7開始使用,用于替代NSURLConnection進行網(wǎng)絡數(shù)據(jù)傳輸?shù)念悺V腁FNetworking庫的2.0版本采用的NSURLConnection,但是從3.0版本開始,已經(jīng)用NSURLSession替換了NSURLConnection。
NSURLSession可以與delegate(代理)綁定,在一個會話的生命周期內(nèi),delegate會被某些事件調用,例如服務端認證或者確定加載的資源是否應該轉化為下載。
NSURLSession實例是線程安全的,它會創(chuàng)建NSURLSessionTask對象來執(zhí)行數(shù)據(jù)的加載。被創(chuàng)建的NSURLSessionTask對象初始化狀態(tài)是suspend(掛起),需要調用resume(恢復)方法來執(zhí)行。
NSURLSessionTask
NSURLSessionTask有四個子類:NSURLSessionDataTask、NSURLSessionUploadTask和NSURLSessionDownloadTask,NSURLSessionStreamTask。
- NSURLSessionDataTask用于執(zhí)行普通的任務,例如請求或上傳數(shù)據(jù)。
- NSURLSessionUploadTask繼承自NSURLSessionUploadTask用于上傳文件或數(shù)據(jù)到服務器。
- NSURLSessionDownloadTask會直接將響應數(shù)據(jù)寫入臨時文件,默認下載到沙盒的temp目錄下。下載完成后,delegate會接收到URLSession:downloadTask:didFinishDownloadingToURL: 消息。
- NSURLSessionStreamTask用于建立一個 TCP/IP 連接,自iOS9以后開始使用。
NSURLSessionConfiguration
NSURLSessionConfiguration是NSURLSession的配置類,用于生成NSURLSession對象。
NSURLSessionConfiguration有三種初始化方式:
- defaultSessionConfiguration。返回的全局會話使用磁盤來緩存credential, cache and cookie。
- ephemeralSessionConfiguration。返回的臨時會話使用內(nèi)存而不使用磁盤來緩存credential, cache and cookie,app一旦退出,數(shù)據(jù)會被清空。
- backgroundSessionConfiguration。返回的后臺
會話可以在app被掛起時執(zhí)行網(wǎng)絡操作,但必須要傳入一個NSString類型的identifier。
NSURLSession使用
NSURLSession提供了兩種方法來創(chuàng)建會話:
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
第二個方法可以傳入delegate來監(jiān)聽會話事件,delegate需要遵循NSURLSessionDelegate協(xié)議且會被強引用,還可以傳入NSOperationQueue對象來指定delegate在哪個隊列被調用,傳入值為nil時,session會默認創(chuàng)建一個串行隊列來執(zhí)行delegate的方法。
創(chuàng)建完會話之后,需要創(chuàng)建一個任務來執(zhí)行具體的網(wǎng)絡傳輸操作。
// 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;
普通任務獲取資訊列表:
// 配置URL
NSURL *url = [NSURL URLWithString:@"http://toutiao-ali.juheapi.com/toutiao/index"];
// 配置URLRequest
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setValue:@"APPCODE fd4e0a674e274e46ad3e26ab508ff21c" forHTTPHeaderField:@"Authorization"];
// 配置全局會話
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
// 返回掛起的普通任務
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);
}];
// 恢復普通任務
[dataTask resume];
執(zhí)行resume方法后任務才會開始加載數(shù)據(jù),并在回調中返回響應,不然task永遠是掛起狀態(tài)。
下載任務下載圖片資源:
// 配置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"];
// 配置全局會話
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
// 返回掛起的下載任務
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 返回沙盒tmp目錄的臨時文件
NSLog(@"%@", location);
}];
// 恢復下載任務
[downloadTask resume];
通過代理方法實現(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"];
// 配置全局會話
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
// 傳入代理對象
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
// 返回掛起的普通任務,不用completionHandler返回數(shù)據(jù)
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url];
// 恢復下載任務
[dataTask resume];
會話初始化時將self作為代理對象傳入,代理對象需要遵循NSURLSessionDataDelegate協(xié)議和NSURLSessionTaskDelegate協(xié)議,任務在執(zhí)行過程中通知代理對象具體的執(zhí)行步驟。
#pragma mark NSURLSessionDataDelegate
/**
任務收到服務器的初始響應
@param session 用戶創(chuàng)建的會話
@param dataTask 用戶創(chuàng)建的數(shù)據(jù)任務
@param response 服務器響應
@param completionHandler 回調,告知系統(tǒng)是否繼續(xù)傳輸
*/
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
// 是否允許繼續(xù)傳輸數(shù)據(jù)
NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
// 響應內(nèi)容的預期長度,若預期長度未知,返回-1
NSInteger expected = (NSInteger)response.expectedContentLength;
expected = expected > 0 ? expected : 0;
// 不執(zhí)行此行代碼,默認取消傳輸
completionHandler(disposition);
}
/**
任務收到服務器返回的數(shù)據(jù)(可能多次調用)
@param session 用戶創(chuàng)建的會話
@param dataTask 用戶創(chuàng)建的數(shù)據(jù)任務
@param data 當次返回的數(shù)據(jù)
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
if (!self.jjData) {
self.jjData = [[NSMutableData alloc] init];
}
// 拼接當次返回的數(shù)據(jù)
[self.jjData appendData:data];
// 計算當前總數(shù)據(jù)長度
const NSInteger totalSize = self.jjData.length;
NSLog(@"當前數(shù)據(jù)大小:%ld", totalSize);
}
#pragma mark NSURLSessionTaskDelegate
/**
任務完成數(shù)據(jù)傳輸
@param session 用戶創(chuàng)建的會話
@param task 用戶創(chuàng)建的任務
@param error 錯誤信息
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (nil == error) {
NSLog(@"總數(shù)據(jù)大?。?ld", self.jjData.length);
}
}
假如需要實時顯示加載進度,在
URLSession:dataTask:didReceiveResponse:responsecompletionHandler:方法中獲取響應內(nèi)容的預期大小,在URLSession:dataTask:didReceiveData:方法的中獲取當前數(shù)據(jù)的大小,最后在URLSession:task:didCompleteWithError:方法中關閉加載進度。
除了resmue方法,URLSessionTask還提供了暫停和取消的方法。
// 暫停任務
- (void)suspend;
// 取消任務
- (void)cancel;
總結
學習NSURLSession的目的是為了之后學習SDWebImage的Downloader模塊,Downloader是SDWebimage的核心模塊,包含了兩大類SDWebImageDownloader和SDWebImageDownloaderOperation。在學習SDWebImageDownloaderOperation時,會對NSURLSession的應用做進一步的闡述。
AFNetworking庫也是基于NSURLSession封裝的,等學習完SDWebImage的源碼,筆者會研究AFNetworking的源碼,希望今天的學習能起到一些幫助作用。