2013年的WWDC大會(huì)上,蘋果推出了NSURLSession,對(duì)Foundation URL加載系統(tǒng)進(jìn)行了徹底的重構(gòu),提供了更豐富的API來(lái)處理網(wǎng)絡(luò)請(qǐng)求,如:支持http2.0協(xié)議、直接把數(shù)據(jù)下載到磁盤、同一session發(fā)送多個(gè)請(qǐng)求、下載是多線程異步處理和提供全局的session并可以統(tǒng)一配置等等,提高了NSURLSession的易用性、靈活性,更加地適合移動(dòng)開(kāi)發(fā)的需求。
NSURLSession的介紹
1. session類型
Default session
+defaultSessionConfiguration 返回一個(gè)標(biāo)準(zhǔn)的 configuration,這個(gè)配置實(shí)際上與 NSURLConnection 的網(wǎng)絡(luò)堆棧(networking stack)是一樣的,具有相同的共享 NSHTTPCookieStorage,共享 NSURLCache 和共享 NSURLCredentialStorage。
Ephemeral session
+ephemeralSessionConfiguration 返回一個(gè)預(yù)設(shè)配置,這個(gè)配置中不會(huì)對(duì)緩存Cookie 和證書進(jìn)行持久性的存儲(chǔ),這對(duì)于實(shí)現(xiàn)像秘密瀏覽這種功能來(lái)說(shuō)是很理想的。
Background session
+backgroundSessionConfiguration:(NSString *)identifier 的獨(dú)特之處在于,它會(huì)創(chuàng)建一個(gè)后臺(tái) session。后臺(tái) session 不同于常規(guī)的,普通的 session,它甚至可以在應(yīng)用程序掛起,退出或者崩潰的情況下進(jìn)行上傳和下載任務(wù)。初始化時(shí)指定的標(biāo)識(shí)符,被用于向任何可能在進(jìn)程外恢復(fù)后臺(tái)傳輸?shù)氖刈o(hù)進(jìn)程。
2. 配置屬性
基本配置
HTTPAdditionalHeaders 指定了一組默認(rèn)的可以設(shè)置請(qǐng)求(outbound request)的數(shù)據(jù)頭。這對(duì)于跨 session 共享信息,如內(nèi)容類型、語(yǔ)言、用戶代理和身份認(rèn)證,是很有用的。
// 設(shè)置請(qǐng)求的header
NSString *userPasswordString = [NSString stringWithFormat:@"%@:%@", user, password];
NSData * userPasswordData = [userPasswordString dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64EncodedCredential = [userPasswordData base64EncodedStringWithOptions:0];
NSString *authString = [NSString stringWithFormat:@"Basic %@", base64EncodedCredential];
NSString *userAgentString = @"AppName/com.example.app (iPhone 5s; iOS 7.0.2; Scale/2.0)";
configuration.HTTPAdditionalHeaders = @{@"Accept": @"application/json",
@"Accept-Language": @"en",
@"Authorization": authString,
@"User-Agent": userAgentString};
-
networkServiceType對(duì)標(biāo)準(zhǔn)的網(wǎng)絡(luò)流量、網(wǎng)絡(luò)電話、語(yǔ)音、視頻,以及由一個(gè)后臺(tái)進(jìn)程使用的流量進(jìn)行了區(qū)分。大多數(shù)應(yīng)用程序都不需要設(shè)置這個(gè)。 -
allowsCellularAccess和discretionary被用于節(jié)省通過(guò)蜂窩網(wǎng)絡(luò)連接的帶寬。對(duì)于后臺(tái)傳輸?shù)那闆r,推薦大家使用discretionary這個(gè)屬性,而不是allowsCellularAccess,因?yàn)榍罢邥?huì)把WiFi和電源的可用性考慮在內(nèi)。 -
timeoutIntervalForRequest和timeoutIntervalForResource分別指定了對(duì)于請(qǐng)求和資源的超時(shí)間隔。許多開(kāi)發(fā)人員試圖使用timeoutInterval去限制發(fā)送請(qǐng)求的總時(shí)間,但其實(shí)它真正的含義是:分組(packet)之間的時(shí)間。實(shí)際上我們應(yīng)該使用timeoutIntervalForResource來(lái)規(guī)定整體超時(shí)的總時(shí)間,但應(yīng)該只將其用于后臺(tái)傳輸,而不是用戶實(shí)際上可能想要去等待的任何東西。 -
HTTPMaximumConnectionsPerHost是Foundation框架中URL加載系統(tǒng)的一個(gè)新的配置選項(xiàng)。它曾經(jīng)被NSURLConnection用于管理私有的連接池?,F(xiàn)在有了NSURLSession,開(kāi)發(fā)者可以在需要時(shí)限制連接到特定主機(jī)的數(shù)量。 -
HTTPShouldUsePipelining這個(gè)屬性在NSMutableURLRequest下也有,它可以被用于開(kāi)啟HTTP管線化(HTTP pipelining),這可以顯著降低請(qǐng)求的加載時(shí)間,但是由于沒(méi)有被服務(wù)器廣泛支持,默認(rèn)是禁用的。 -
sessionSendsLaunchEvents是另一個(gè)新的屬性,該屬性指定該session是否應(yīng)該從后臺(tái)啟動(dòng)。 -
connectionProxyDictionary指定了session連接中的代理服務(wù)器。同樣地,大多數(shù)面向消費(fèi)者的應(yīng)用程序都不需要代理,所以基本上不需要配置這個(gè)屬性。
Cookie 策略
-
HTTPCookieStorage存儲(chǔ)了session所使用的cookie。默認(rèn)情況下會(huì)使用NSHTTPCookieShorage的+sharedHTTPCookieStorage這個(gè)單例對(duì)象,這與NSURLConnection是相同的。 -
HTTPCookieAcceptPolicy決定了什么情況下session應(yīng)該接受從服務(wù)器發(fā)出的cookie。 -
HTTPShouldSetCookies指定了請(qǐng)求是否應(yīng)該使用session存儲(chǔ)的cookie,即HTTPCookieSorage屬性的值。
安全策略
-
URLCredentialStorage存儲(chǔ)了session所使用的證書。默認(rèn)情況下會(huì)使用NSURLCredentialStorage的+sharedCredentialStorage這個(gè)單例對(duì)象,這與NSURLConnection是相同的。 -
TLSMaximumSupportedProtocol和TLSMinimumSupportedProtocol確定 `session 是否支持 SSL 協(xié)議。
緩存策略
-
URLCache是session使用的緩存。默認(rèn)情況下會(huì)使用NSURLCache的+sharedURLCache這個(gè)單例對(duì)象,這與NSURLConnection是相同的。 -
requestCachePolicy指定了一個(gè)請(qǐng)求的緩存響應(yīng)應(yīng)該在什么時(shí)候返回。這相當(dāng)于NSURLRequest的-cachePolicy方法。
自定義協(xié)議
protocolClasses 用來(lái)配置特定某個(gè) session 所使用的自定義協(xié)議(該協(xié)議是 NSURLProtocol 的子類)的數(shù)組。
3. NSURLSessionTask
NSURLsessionTask 是一個(gè)抽象類,其下有 3 個(gè)實(shí)體子類可以直接使用:NSURLSessionDataTask、NSURLSessionUploadTask、NSURLSessionDownloadTask。這 3 個(gè)子類封裝了現(xiàn)代程序三個(gè)最基本的網(wǎng)絡(luò)任務(wù):獲取數(shù)據(jù),比如 JSON 或者 XML,上傳文件和下載文件。

不同于直接使用 alloc-init 初始化方法,task 是由一個(gè) NSURLSession 創(chuàng)建的。每個(gè) task 的構(gòu)造方法都對(duì)應(yīng)有或者沒(méi)有 completionHandler 這個(gè) block 的兩個(gè)版本。
4. 代理
針對(duì)NSURLsessionTask的代理,根代理為NSURLSessionDelegate,其它的代理直接或者間接繼承自改代理,如:NSURLSessionTaskDelegate、NSURLSessionDataDelegate、NSURLSessionDownloadDelegate。其中根代理NSURLSessionDelegate主要處理鑒權(quán)、后臺(tái)下載任務(wù)完成通知等等,NSURLSessionTaskDelegate主要處理收到鑒權(quán)響應(yīng)、任務(wù)結(jié)束(無(wú)論是正常還是異常),NSURLSessionDataDelegate處理數(shù)據(jù)的接收、dataTask轉(zhuǎn)downloadTask、緩存等,NSURLSessionDownloadDelegate主要處理數(shù)據(jù)下載、數(shù)據(jù)進(jìn)度通知等。

NSURLSession應(yīng)用
1. NSURLSessionDataTask 發(fā)送 GET 請(qǐng)求
//確定請(qǐng)求路徑
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520&pwd=520&type=JSON"];
//創(chuàng)建 NSURLSession 對(duì)象
NSURLSession *session = [NSURLSession sharedSession];
/**
根據(jù)對(duì)象創(chuàng)建 Task 請(qǐng)求,默認(rèn)在子線程中解析數(shù)據(jù)
url 方法內(nèi)部會(huì)自動(dòng)將 URL 包裝成一個(gè)請(qǐng)求對(duì)象(默認(rèn)是 GET 請(qǐng)求)
completionHandler 完成之后的回調(diào)(成功或失?。?
param data 返回的數(shù)據(jù)(響應(yīng)體)
param response 響應(yīng)頭
param error 錯(cuò)誤信息
*/
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:
^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//解析服務(wù)器返回的數(shù)據(jù)
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];
//發(fā)送請(qǐng)求(執(zhí)行Task)
[dataTask resume];
2. NSURLSessionDataTask 發(fā)送 POST 請(qǐng)求
//確定請(qǐng)求路徑
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
//創(chuàng)建可變請(qǐng)求對(duì)象
NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url];
//修改請(qǐng)求方法
requestM.HTTPMethod = @"POST";
//設(shè)置請(qǐng)求體
requestM.HTTPBody = [@"username=520&pwd=520&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
//創(chuàng)建會(huì)話對(duì)象
NSURLSession *session = [NSURLSession sharedSession];
//創(chuàng)建請(qǐng)求 Task
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:requestM completionHandler:
^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//解析返回的數(shù)據(jù)
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];
//發(fā)送請(qǐng)求
[dataTask resume];
3. NSURLSessionDataTask 設(shè)置代理發(fā)送請(qǐng)求
//確定請(qǐng)求路徑
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
//創(chuàng)建可變請(qǐng)求對(duì)象
NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url];
//設(shè)置請(qǐng)求方法
requestM.HTTPMethod = @"POST";
//設(shè)置請(qǐng)求體
requestM.HTTPBody = [@"username=520&pwd=520&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
//創(chuàng)建會(huì)話對(duì)象,設(shè)置代理
/**
第一個(gè)參數(shù):配置信息
第二個(gè)參數(shù):設(shè)置代理
第三個(gè)參數(shù):隊(duì)列,如果該參數(shù)傳遞nil 那么默認(rèn)在子線程中執(zhí)行
*/
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self delegateQueue:nil];
//創(chuàng)建請(qǐng)求 Task
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:requestM];
//發(fā)送請(qǐng)求
[dataTask resume];
代理方法:
-(void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask
didReceiveResponse:(nonnull NSURLResponse *)response
completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler {
//子線程中執(zhí)行
NSLog(@"接收到服務(wù)器響應(yīng)的時(shí)候調(diào)用 -- %@", [NSThread currentThread]);
self.dataM = [NSMutableData data];
//默認(rèn)情況下不接收數(shù)據(jù)
//必須告訴系統(tǒng)是否接收服務(wù)器返回的數(shù)據(jù)
completionHandler(NSURLSessionResponseAllow);
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
NSLog(@"接受到服務(wù)器返回?cái)?shù)據(jù)的時(shí)候調(diào)用,可能被調(diào)用多次");
//拼接服務(wù)器返回的數(shù)據(jù)
[self.dataM appendData:data];
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSLog(@"請(qǐng)求完成或者是失敗的時(shí)候調(diào)用");
//解析服務(wù)器返回?cái)?shù)據(jù)
NSLog(@"%@", [[NSString alloc] initWithData:self.dataM encoding:NSUTF8StringEncoding]);
}
設(shè)置代理之后的強(qiáng)引用問(wèn)題
-
NSURLSession對(duì)象在使用的時(shí)候,如果設(shè)置了代理,那么session會(huì)對(duì)代理對(duì)象保持一個(gè)強(qiáng)引用,在合適的時(shí)候應(yīng)該主動(dòng)進(jìn)行釋放 - 可以在控制器調(diào)用
viewDidDisappear方法的時(shí)候來(lái)進(jìn)行處理,通過(guò)調(diào)用invalidateAndCancel方法或者是finishTasksAndInvalidate方法來(lái)釋放對(duì)代理對(duì)象的強(qiáng)引用。
其中,invalidateAndCancel是直接取消請(qǐng)求然后釋放代理對(duì)象,而finishTasksAndInvalidate是等請(qǐng)求完成之后釋放代理對(duì)象。
4. NSURLSessionDownloadTask 簡(jiǎn)單下載
//確定請(qǐng)求路徑
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"];
//創(chuàng)建請(qǐng)求對(duì)象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//創(chuàng)建會(huì)話對(duì)象
NSURLSession *session = [NSURLSession sharedSession];
//創(chuàng)建會(huì)話請(qǐng)求
//優(yōu)點(diǎn):該方法內(nèi)部已經(jīng)完成了邊接收數(shù)據(jù)邊寫沙盒的操作,解決了內(nèi)存飆升的問(wèn)題
NSURLSessionDownloadTask *downTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//默認(rèn)存儲(chǔ)到臨時(shí)文件夾 tmp 中,需要剪切文件到 cache
NSLog(@"%@", location);//目標(biāo)位置
NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]
stringByAppendingPathComponent:response.suggestedFilename];
/**
fileURLWithPath:有協(xié)議頭
URLWithString:無(wú)協(xié)議頭
*/
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
}];
//發(fā)送請(qǐng)求
[downTask resume];
以上方法無(wú)法監(jiān)聽(tīng)下載進(jìn)度,如要獲取下載進(jìn)度,可以使用代理的方式進(jìn)行下載。
5. NSURLSessionDownloadTask 代理方式
NSURL * url = [NSURL URLWithString:@"http://e.hiphotos.baidu.com/image/pic/item/63d0f703918fa0ec14b94082249759ee3c6ddbc6.jpg"];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];
NSURLSessionDownloadTask * downloadTask =[ defaultSession downloadTaskWithURL:url];
[downloadTask resume];
代理方法:
// 接收數(shù)據(jù),可能多次被調(diào)用
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
float progress = totalBytesWritten * 1.0/totalBytesExpectedToWrite;
// 主線程更新UI
dispatch_async(dispatch_get_main_queue(),^ {
[self.process setProgress:progress animated:YES];
});
}
// 3.下載完成之后調(diào)用該方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
NSString *catchDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [catchDir stringByAppendingPathComponent:@"app.dmg"];
NSError *fileError = nil;
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
[[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&fileError];
if (fileError) {
NSLog(@"保存下載文件出錯(cuò):%@", fileError);
} else {
NSLog(@"保存成功:%@", filePath);
}
}
暫停和恢復(fù)下載:
方式一:
// 暫停下載
- (IBAction)suspendDownload {
if (self.session) {
__weak typeof(self) weakSelf = self;
[self.task cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
weakSelf.receivedData = resumeData;
}];
}
}
// 恢復(fù)下載
- (IBAction)resumeDownload {
if (self.session) {
self.task = [self.session downloadTaskWithResumeData:self.receivedData];
}
[self.task resume];
}
方式二:
//暫停
[self.downloadTask suspend];
//恢復(fù)
[self.downloadTask resume];
6. NSURLSessionDownloadTask 后臺(tái)下載
// 后臺(tái)session
- (NSURLSession* ) backgroundURLSession {
static NSURLSession * session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString * identifier = @"com.yourcompany.appId.BackgroundSession";
NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier];
session = [NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
});
return session;
}
// 創(chuàng)建并啟動(dòng)任務(wù)
- (void)beginDownloadWithUrl:(NSString *)downloadURLString {
NSURL *downloadURL = [NSURL URLWithString:downloadURLString];
NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];
NSURLSession *session = [self backgroundURLSession];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request];
[downloadTask resume];
}
在appDelegate中實(shí)現(xiàn)application:handleEventsForBackgroundURLSession:completionHandler:方法,在后臺(tái)所有的任務(wù)完成后會(huì)調(diào)用給方法,但是我一直沒(méi)有調(diào)用成功,原因未知,高手可以告知一下
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
NSURLSession *backgroundSession = [self backgroundURLSession];
NSLog(@"Rejoining session with identifier %@ %@", identifier, backgroundSession);
// 保存 completion handler 以在處理 session 事件后更新 UI
[self addCompletionHandler:completionHandler forSession:identifier];
}
handleEventsForBackgroundURLSession 方法是在后臺(tái)下載的所有任務(wù)完成后才會(huì)調(diào)用。如果后臺(tái)任務(wù)完成且應(yīng)用被殺掉,啟動(dòng)應(yīng)用程序后,該方法會(huì)在 application:didFinishLaunchingWithOptions:方法被調(diào)用之后被調(diào)用。
//NSURLSessionDelegate委托方法,會(huì)在NSURLSessionDownloadDelegate委托方法后執(zhí)行
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
NSLog(@"Background URL session %@ finished events.\n", session);
}
之后會(huì)調(diào)用接收完成的方法:
/*
* 在該方法結(jié)束前,需要處理location指向的文件,因?yàn)榉椒ńY(jié)束后,臨時(shí)文件會(huì)被銷毀
* 如果用模擬器保存,會(huì)出錯(cuò),因?yàn)槟M器上app退出后再啟動(dòng)是,路徑會(huì)不一樣,導(dǎo)致找不到后臺(tái)下載的文件;而用真機(jī)調(diào)試則無(wú)此問(wèn)題 ?。?!
*/
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{}
/*
* 該方法下載成功和失敗都會(huì)回調(diào),只是失敗的是error是有值的,
* 在下載失敗時(shí),error的userinfo屬性可以通過(guò)NSURLSessionDownloadTaskResumeData
* 這個(gè)key來(lái)取到resumeData(和上面的resumeData是一樣的),再通過(guò)resumeData恢復(fù)下載
*/
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{}
7. NSURLSessionUploadTask上傳任務(wù)
NSURL*URL = [NSURLURLWithString:@"http://example.com/upload"];
NSURLRequest*request = [NSURLRequestrequestWithURL:URL];
NSData*data = ...;
NSURLSession*session = [NSURLSessionsharedSession];
NSURLSessionUploadTask*uploadTask = [session uploadTaskWithRequest:request fromData:datacompletionHandler:^(NSData*data, NSURLResponse *response,NSError*error) {
// ...
}];
[uploadTask resume];
注意事項(xiàng)
1. 后臺(tái)下載的配置和限制
作為一個(gè)必須實(shí)現(xiàn)的委托,您不能對(duì)NSURLSession使用簡(jiǎn)單的基于 block的回調(diào)方法。后臺(tái)啟動(dòng)應(yīng)用程序,是相對(duì)耗費(fèi)較多資源的,所以總是采用HTTP重定向。后臺(tái)傳輸服務(wù)只支持HTTP和HTTPS,你不能使用自定義的協(xié)議。系統(tǒng)會(huì)根據(jù)可用的資源進(jìn)行優(yōu)化,在任何時(shí)候你都不能強(qiáng)制傳輸任務(wù)在后臺(tái)進(jìn)行。
另外,要注意的是在后臺(tái)會(huì)話中,NSURLSessionDataTasks 是完全不支持的,你應(yīng)該只出于短期的、小請(qǐng)求等使用這些任務(wù),而不是用來(lái)下載或上傳。
2. 后臺(tái)啟動(dòng)新的下載
蘋果會(huì)對(duì)后臺(tái)的下載任務(wù)進(jìn)行限制,大致流程如下:
- 蘋果的
NSURLSession這個(gè)類會(huì)維護(hù)一個(gè)Delay值(即延時(shí)執(zhí)行時(shí)間),用于后臺(tái)啟動(dòng)任務(wù)延時(shí)執(zhí)行時(shí)使用; - 當(dāng)在后臺(tái)啟動(dòng)一個(gè)新任務(wù)時(shí),蘋果會(huì)對(duì)這個(gè)任務(wù)進(jìn)行延時(shí)執(zhí)行,延時(shí)時(shí)間蘋果那邊是有一個(gè)默認(rèn)的延時(shí)時(shí)間,當(dāng)后臺(tái)啟動(dòng)的任務(wù)數(shù)越多,這個(gè)值就會(huì)成
2的N-1冪倍增長(zhǎng); - 比如:假設(shè)蘋果設(shè)定的延時(shí)時(shí)間為
Delay。當(dāng)在后臺(tái)啟動(dòng)了第一個(gè)任務(wù)時(shí),這個(gè)任務(wù)的延時(shí)時(shí)間為Delay,這個(gè)任務(wù)會(huì)在Delay時(shí)間后開(kāi)始執(zhí)行;當(dāng)啟動(dòng)在后臺(tái)啟動(dòng)第二個(gè)任務(wù)時(shí),這個(gè)任務(wù)的延時(shí)時(shí)間為:2 * Delay,當(dāng)啟動(dòng)第三個(gè)任務(wù)是,該任務(wù)的延時(shí)執(zhí)行時(shí)間即為:2 * 2 * Delay;以此類推,在后臺(tái)啟動(dòng)第N個(gè)任務(wù)是,該任務(wù)的延時(shí)執(zhí)行時(shí)間為:2^(N-1)次方 * Delay; - 但是在應(yīng)用從后臺(tái)切到前臺(tái)或者重新啟動(dòng)時(shí),這個(gè)延時(shí)時(shí)間會(huì)重置。
參考示例:
https://github.com/BirdandLion/NSURLSessionDemo
參考資料:
Life Cycle of a URL Session
http://www.itdecent.cn/p/63e2ad28459f
http://www.itdecent.cn/p/b0ddadd34037