USURLSession基本使用介紹
在2013的WWDC上弊琴,蘋(píng)果推出了NSURLConnection的繼任者NSURLSession,并且在iOS9.0之后攘乒,以前使用的NSURLConnection將提示過(guò)期义屏,推薦使用NSURLSession來(lái)替換NSURLConnection完成網(wǎng)路請(qǐng)求相關(guān)操作。與 NSURLConnection 一樣溃蔫,NSURLSession 指的也不僅是同名類(lèi) NSURLSession,還包括一系列相互關(guān)聯(lián)的類(lèi)琳猫。NSURLSession 包括了與之前相同的組件伟叛,NSURLRequest 與 NSURLCache,但是把 NSURLConnection 替換成了 NSURLSession脐嫂、NSURLSessionConfiguration 以及 NSURLSessionTask 的 3 個(gè)子類(lèi):NSURLSessionDataTask统刮,NSURLSessionUploadTask,NSURLSessionDownloadTask账千,這三個(gè)子類(lèi)可以直接使用侥蒙,每個(gè)任務(wù)都可以?huà)炱穑╯uspend),結(jié)束(cancel) 和 執(zhí)行(resume)匀奏,調(diào)用響應(yīng)的函數(shù)即可
</br>
與 NSURLConnection 相比鞭衩,NSURLsession 最直接的改進(jìn)就是可以配置每個(gè) session 的緩存,協(xié)議娃善,cookie论衍,以及證書(shū)策略(credential policy),甚至跨程序共享這些信息聚磺。這將允許程序和網(wǎng)絡(luò)基礎(chǔ)框架之間相互獨(dú)立饲齐,不會(huì)發(fā)生干擾。每個(gè) NSURLSession 對(duì)象都由一個(gè) NSURLSessionConfiguration 對(duì)象來(lái)進(jìn)行初始化咧最,后者指定了剛才提到的那些策略以及一些用來(lái)增強(qiáng)移動(dòng)設(shè)備上性能的新選項(xiàng)。
1、NSURLSessionDataTask 獲取服務(wù)器上的數(shù)據(jù)矢沿,返回相關(guān)數(shù)據(jù)滥搭,獲取后直接處理
2、NSURLSessionUploadTask 創(chuàng)建一個(gè)上傳任務(wù)捣鲸,在上傳時(shí)需要制定文件源或數(shù)據(jù)源瑟匆,一般來(lái)說(shuō),對(duì)于一個(gè)上傳任務(wù)栽惶,也會(huì)收到服務(wù)的響應(yīng)也會(huì)有相關(guān)數(shù)據(jù)返回愁溜,所以NSURLSessionUploadTask繼承于NSURLSessionDataTask
3、NSURLSessionDownloadTask 下載服務(wù)器上的數(shù)據(jù)外厂,當(dāng)任務(wù)結(jié)束的時(shí)候冕象,他會(huì)帶回一個(gè)下載文件的一個(gè)臨時(shí)文件路徑,所以在下載大容量任務(wù)時(shí)汁蝶,使用尤為方便渐扮。
每一個(gè)task都是可以取消,暫鸵疵蓿或者恢復(fù)的墓律。當(dāng)一個(gè) download task 取消時(shí),可以通過(guò)選項(xiàng)來(lái)創(chuàng)建一個(gè)恢復(fù)數(shù)據(jù)(resume data)幔亥,然后可以傳遞給下一次新創(chuàng)建的 download task耻讽,以便繼續(xù)之前的下載,這在斷點(diǎn)下載的時(shí)候尤為有用帕棉。
NSURLSession常用的類(lèi)
1针肥、NSURL:根據(jù)url生成的請(qǐng)求地址
2、NSURLRequest:封裝的一個(gè)請(qǐng)求笤昨,攜帶發(fā)送給服務(wù)器的全部數(shù)據(jù)祖驱,里面包含一個(gè)NSURL對(duì)象,請(qǐng)求方法瞒窒,請(qǐng)求頭捺僻,請(qǐng)求體等等。
3崇裁、NSMutableURLRequest:這個(gè)是NSURLRequest的子類(lèi)匕坯,通過(guò)名字我們可以看出這是一個(gè)可變的對(duì)象,我們可以在這里自定義設(shè)置發(fā)送的服務(wù)器的全部數(shù)據(jù)(超市等待時(shí)間拔稳、請(qǐng)求方法葛峻、請(qǐng)求體、請(qǐng)求頭)
4巴比、NSURLResponse:服務(wù)的響應(yīng)類(lèi)术奖,和NSURLRequest對(duì)象礁遵,包含服務(wù)返回的響應(yīng)頭部數(shù)據(jù)
5、NSURLSessionConfiguration 用于配置會(huì)話(huà)的屬性采记,可以通過(guò)該類(lèi)配置會(huì)話(huà)的工作模式:
+ (NSURLSessionConfiguration *)defaultSessionConfiguration; 工作模式類(lèi)似于原來(lái)的NSURLConnection佣耐,可以使用緩存的Cache,Cookie唧龄,鑒權(quán)
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration; 不使用緩存的Cache兼砖,Cookie,鑒權(quán)既棺。
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier; 創(chuàng)建一個(gè)后臺(tái) session讽挟,后臺(tái) session 不同于常規(guī)的,普通的 session丸冕,它甚至可以在應(yīng)用程序掛起耽梅,退出或者崩潰的情況下運(yùn)行上傳和下載任務(wù),創(chuàng)建Configuration對(duì)象的時(shí)候需要給一個(gè)NSString的ID用于用于標(biāo)記后臺(tái)的session晨仑。(稍后詳細(xì)描述)
6褐墅、NSURLSession:會(huì)話(huà)對(duì)象
NSURLSession的使用步驟
1、根據(jù)url創(chuàng)建一個(gè)NSURL對(duì)象
2洪己、根據(jù)創(chuàng)建的NSURL創(chuàng)建一個(gè)NSURLRequest對(duì)象妥凳,創(chuàng)建請(qǐng)求對(duì)象(此對(duì)象內(nèi)容全部都是默認(rèn)值,如:請(qǐng)求方法默認(rèn)是GET)答捕,如果想要自定數(shù)據(jù)則創(chuàng)建NSMutableURLRequest對(duì)象
3逝钥、創(chuàng)建會(huì)話(huà)對(duì)象NSURLSession,創(chuàng)建NSURLSession對(duì)象有三種方法:
1)+ (NSURLSession *)sharedSession; 返回一個(gè)默認(rèn)的NSURLSession拱镐,使用共享的會(huì)話(huà)艘款,該會(huì)話(huà)使用全局的Cache,Cookie和證書(shū)
2)+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration; 返回一個(gè)根據(jù)剛才創(chuàng)建的Configuration的NSURLSession對(duì)象沃琅,系統(tǒng)默認(rèn)創(chuàng)建一個(gè)新的OperationQueue處理Session的消息
3)+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue; 返回一個(gè)根據(jù)剛才創(chuàng)建的Configuration的NSURLSession對(duì)象哗咆,可以設(shè)定回調(diào)的delegate(注意這個(gè)回調(diào)delegate會(huì)被強(qiáng)引用),并且可以設(shè)定delegate在哪個(gè)OperationQueue回調(diào)益眉,如果我們將其設(shè)置為[NSOperationQueue mainQueue]就能在主線(xiàn)程進(jìn)行回調(diào)非常的方便
4晌柬、使用創(chuàng)建好的NSURLSession對(duì)象和NSURLRequest對(duì)象創(chuàng)建一個(gè)NSURLSessionTask任務(wù),NSURLSessionDataTask郭脂、NSURLSessionUploadTask 或者 NSURLSessionDownloadTask
5感昼、調(diào)用resume開(kāi)始工作
6鳄袍、當(dāng)不再需要連接調(diào)用Session的invalidateAndCancel直接關(guān)閉写半,或者調(diào)用finishTasksAndInvalidate等待當(dāng)前Task結(jié)束后關(guān)閉畅卓。這時(shí)Delegate會(huì)收到URLSession:didBecomeInvalidWithError:這個(gè)事件。Delegate收到這個(gè)事件之后會(huì)被解引用莹弊。
</br>
和NSURLConnection一樣涤久,NSURLSession也提供了兩種形式的使用涡尘,代理模式和非代理模式
非代理模式
每個(gè)task的構(gòu)造方法都提供了一個(gè)–dataTaskWithRequest:completionHandler:
的函數(shù),類(lèi)似NSURLConnection的sendAsynchronousRequest:queue:completionHandler:
和sendSynchronousRequest:returningResponse:error:
模式响迂,只是NSURLSession僅有異步版本悟衩。
例如,如果創(chuàng)建一個(gè)NSURLSessionDataTask任務(wù):
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
//接受的數(shù)據(jù)data栓拜、服務(wù)器響應(yīng)response、錯(cuò)誤代碼error
}];
//啟動(dòng)task
[task resume];
//其它方法惠昔,如取消任務(wù)幕与,暫停任務(wù)等
//[task cancel];
//[task suspend]
再者創(chuàng)建一個(gè)NSURLSessionUploadTask任務(wù)
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
NSData *data = ...; //上傳任務(wù)需要一個(gè)需要上傳的NSData對(duì)象或者一個(gè)本地文件路徑對(duì)應(yīng)的NSURL
NSURLSessionDataTask *uploadTask = [self.session uploadTaskWithRequest:request
fromData:data
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
//接受的數(shù)據(jù)data、服務(wù)器響應(yīng)response镇防、錯(cuò)誤代碼error
}];
//啟動(dòng)task
[uploadTask resume];
//其它方法啦鸣,如取消任務(wù),暫停任務(wù)等
//[uploadTask cancel];
//[uploadTask suspend];
我們?cè)賮?lái)看看NSURLSessionDownloadTask任務(wù)来氧,下載任務(wù)的不同之處在于诫给,NSURLSessionDownloadTask會(huì)一點(diǎn)一點(diǎn)的將下載數(shù)據(jù)寫(xiě)入本地的臨時(shí)文件,回調(diào)block會(huì)帶回一個(gè)下載完成的臨時(shí)文件的地址啦扬,我們需要把文件從這個(gè)臨時(shí)地址移動(dòng)到文件沙盒中保存起來(lái)使用中狂。
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request
completionHandler:
^(NSURL *location, NSURLResponse *response, NSError *error) {
//文件臨時(shí)地址location,服務(wù)器響應(yīng)response扑毡、錯(cuò)誤代碼error
//將臨時(shí)文件移動(dòng)到app沙盒中
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];
}];
//啟動(dòng)task
[downloadTask resume];
//其它方法胃榕,如取消任務(wù),暫停任務(wù)等
//[downloadTask cancel];
//[downloadTask suspend];
代理模式
NSURLSession有幾個(gè)代理協(xié)議NSURLSessionDelegate
瞄摊、NSURLSessionTaskDelegate
勋又、NSURLSessionDataDelegate
、NSURLSessionDownloadDelegate
這幾個(gè)協(xié)議個(gè)呈繼承關(guān)系换帜,NSURLSessionTaskDelegate繼承NSURLSessionDelegate楔壤,NSURLSessionDataDelegate和NSURLSessionDownloadDelegate繼承自NSURLSessionTaskDelegate,實(shí)現(xiàn)不同的任務(wù)惯驼,就實(shí)現(xiàn)相應(yīng)的協(xié)議蹲嚣。在這里我們以NSURLSessionDownloadDelegate協(xié)議為例:
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
//創(chuàng)建下載task
NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request];
//啟動(dòng)task
[downloadTask resume];
//其它方法,如取消任務(wù)跳座,暫停任務(wù)等
//[downloadTask cancel];
//[downloadTask suspend];
代理方法端铛,主要有這么幾個(gè):
//當(dāng)接收到服務(wù)器響應(yīng)的時(shí)候調(diào)用
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
//下載完成之后調(diào)用該方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location;
//當(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ù)大小
//可以在此函數(shù)中計(jì)算下載進(jìn)度
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
//恢復(fù)下載的時(shí)候調(diào)用該方法
//fileOffset:恢復(fù)之后,要從文件的什么地方開(kāi)發(fā)下載
//expectedTotalBytes:該文件數(shù)據(jù)的總大小
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes;
//當(dāng)請(qǐng)求完成之后調(diào)用該方法
//不論是請(qǐng)求成功還是請(qǐng)求失敗都調(diào)用該方法疲眷,如果請(qǐng)求失敗禾蚕,那么error對(duì)象有值,否則那么error對(duì)象為空
//所有方法之中最后調(diào)用
-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error
和NSURLConnection一樣我們這里也介紹一下斷點(diǎn)下載的相關(guān)代碼
第一種:每一個(gè)task都是有三種狀態(tài)掛起狂丝、執(zhí)行和取消换淆,所以我們可以在暫停時(shí)刻掛起任務(wù)哗总,重新下載時(shí)執(zhí)行任務(wù)即可
if (downloadTask.state == NSURLSessionTaskStateSuspended) {
[downloadTask resume];
} else {
[downloadTask suspend];
}
但是很多時(shí)候不是使用這種方法,不知有哪里不妥倍试。讯屈。
第二種:取消的任務(wù)的時(shí)候保存已下載文件的信息,在恢復(fù)下載時(shí)县习,傳入此信息涮母。
//取消下載
[downloadTask cancelByProducingResumeData:^(NSData * __nullable resumeData) {
self.resumeData = resumeData;
}];
//恢復(fù)下載
downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
[downloadTask resume];
比較常用的是這一種。躁愿。
后臺(tái)下載
前面講到我們可以通過(guò)設(shè)置NSURLSessionConfiguration的屬性BackgroundSession來(lái)實(shí)現(xiàn)后臺(tái)下載叛本,在Task執(zhí)行的時(shí)候,用戶(hù)切到后臺(tái)彤钟,Session會(huì)和ApplicationDelegate做交互来候。當(dāng)程序切到后臺(tái)后,在BackgroundSession中的Task還會(huì)繼續(xù)下載逸雹。
在切到后臺(tái)之后营搅,Session的Delegate不會(huì)再收到Task相關(guān)的消息,直到所有Task全都完成后梆砸,系統(tǒng)會(huì)調(diào)用ApplicationDelegate的application:handleEventsForBackgroundURLSession:completionHandler:
回調(diào)转质,之后“匯報(bào)”下載工作,對(duì)于每一個(gè)后臺(tái)下載的Task調(diào)用Session的Delegate中的URLSession:downloadTask:didFinishDownloadingToURL:(成功的話(huà))和URLSession:task:didCompleteWithError:(成功或者失敗都會(huì)調(diào)用)之后調(diào)用Session的Delegate回調(diào)URLSessionDidFinishEventsForBackgroundURLSession:
看一下代碼:
在A(yíng)ppDelegate.m中辫樱,加入后臺(tái)處理函數(shù)
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
self.backgroundTransferCompletionHandler = completionHandler;
}
實(shí)現(xiàn)delegate的-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
方法
// 后臺(tái)傳輸完成峭拘,處理URLSession完成事件
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
//檢查一下是否所有的下載任務(wù)都已經(jīng)完成
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([uploadTasks count] == 0) {
if (appDelegate.backgroundTransferCompletionHandler != nil) {
//在A(yíng)pplicationDelegate被喚醒后,會(huì)有個(gè)參數(shù)ComplietionHandler狮暑,這個(gè)參數(shù)是個(gè)Block鸡挠,這個(gè)參數(shù)要在后面Session的Delegate中didFinish的時(shí)候調(diào)用一下
void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler;
appDelegate.backgroundTransferCompletionHandler = nil;
completionHandler();
}
}
}];
//執(zhí)行其他操作
NSLog(@"All tasks are finished");
}