ios后臺(tái)任務(wù)
ios里,基于設(shè)備續(xù)航和安全方面的考慮猴蹂,不在前臺(tái)運(yùn)行的app會(huì)被系統(tǒng)掛起,所有線程進(jìn)入沉睡態(tài)楣嘁,Ios4之前磅轻,這個(gè)時(shí)機(jī)基本是即時(shí),只要app一進(jìn)入后臺(tái)逐虚,程序馬上就會(huì)被掛起聋溜。ios4后,允許app在后臺(tái)運(yùn)行任務(wù)叭爱,不過(guò)需要注冊(cè)撮躁,而且有各種限制。ios7后买雾,可以在后臺(tái)運(yùn)行的任務(wù)種類(lèi)增加了很多把曼,
大概羅列一下后臺(tái)運(yùn)行的任務(wù)類(lèi)型:
- 通用類(lèi)型任務(wù)
app注冊(cè)后,在退后臺(tái)后有一定的時(shí)間運(yùn)行任務(wù)漓穿,時(shí)間到后app被掛起 - 后臺(tái)播放音樂(lè)
- 位置服務(wù)
- IP電話(VoIP)
- Newsstand
ios7后新增
- 數(shù)據(jù)獲揉途(Background Fetch)
- 推送喚醒(靜默推送,Silent Remote Notifications)
- 后臺(tái)傳輸(Background Transfer Service)
感興趣的同學(xué)可以查看官方文檔或者參考一下文章https://onevcat.com/2013/08/ios7-background-multitask/
因?yàn)樽罱龅絘pp退到后臺(tái)導(dǎo)致上傳超時(shí)失敗的問(wèn)題器净,所以專(zhuān)門(mén)研究了“后臺(tái)傳輸”這個(gè)后臺(tái)任務(wù)的特性和使用方式型雳。
NSURLSession
如果app退到后臺(tái)后,有數(shù)據(jù)在傳輸,這時(shí)候是在當(dāng)前的app進(jìn)程內(nèi)進(jìn)行的纠俭,如果app被掛起沿量,那么線程也就會(huì)被掛起。而IOS7后冤荆,推出了NSURLSession這個(gè)類(lèi)朴则,按照官方說(shuō)明,這個(gè)類(lèi)的行為是由系統(tǒng)托管的钓简,運(yùn)行在另外的進(jìn)程乌妒,不受app生命周期的影響。那就是說(shuō)外邓,即使app被掛起甚至是殺掉撤蚊,系統(tǒng)都可以幫你完成數(shù)據(jù)傳輸。
一旦數(shù)據(jù)傳輸完成:
- 如果app在前臺(tái)损话,那么Task和Session相關(guān)的delegate會(huì)被調(diào)用
- 如果app被掛起侦啸,那么系統(tǒng)先喚醒a(bǔ)pp,然后app的-application:handleEventsForBackgroundURLSession:completionHandler:方法被調(diào)用
- 如果app已經(jīng)被殺死丧枪,從實(shí)際測(cè)試結(jié)果來(lái)看光涂,什么都不會(huì)發(fā)生,只有啟動(dòng)app的時(shí)候拧烦,上面第二種情況的回調(diào)會(huì)被調(diào)用
限制
- 后臺(tái)傳輸只會(huì)通過(guò)wifi來(lái)進(jìn)行
- 數(shù)據(jù)傳輸是離散式或者說(shuō)是碎片式的忘闻,因?yàn)橄到y(tǒng)可能也在運(yùn)行其他的app或者任務(wù),所以數(shù)據(jù)傳輸?shù)臅r(shí)間是不可控的恋博,所以代碼里的超時(shí)邏輯有影響
- 如果是數(shù)據(jù)下載任務(wù)齐佳,文件是存儲(chǔ)在系統(tǒng)提供的臨時(shí)目錄下的,而不是app的沙箱交播,記得要在任務(wù)完成后轉(zhuǎn)移文件
使用方式
- 創(chuàng)建session
- (NSURLSession *)backgroundSession
{
//Use dispatch_once_t to create only one background session. If you want more than one session, do with different identifier
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.yourcompany.appId.BackgroundSession"];
session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
});
return session;
}
2 創(chuàng)建任務(wù)并啟動(dòng)
- (void) beginDownload
{
NSURL *downloadURL = [NSURL URLWithString:DownloadURLString];
NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];
self.session = [self backgroundSession];
self.downloadTask = [self.session downloadTaskWithRequest:request];
[self.downloadTask resume];
}
3 實(shí)現(xiàn)delegate
AppDelegate
//AppDelegate.m
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier
completionHandler:(void (^)())completionHandler
{
//Check if all transfers are done, and update UI
//Then tell system background transfer over, so it can take new snapshot to show in App Switcher
completionHandler();
//You can also pop up a local notification to remind the user
//...
}
Seesion相關(guān)的delegate重虑,這個(gè)函數(shù)在任務(wù)成功或者失敗的時(shí)候被調(diào)用
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error;
Task相關(guān)的delegate,Task有多種秦士,比如上傳任務(wù),下載任務(wù)等永高,不同任務(wù)的回調(diào)會(huì)不同隧土,比如下載任務(wù),能獲得當(dāng)前下載的字節(jié)數(shù)等等
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location;
小結(jié)
URLSession適用于大量數(shù)據(jù)在后臺(tái)傳輸?shù)膱?chǎng)景(小數(shù)據(jù)在app被掛起前應(yīng)該能結(jié)束傳輸)命爬,不過(guò)使用中有諸多限制曹傀,對(duì)代碼模塊的設(shè)計(jì)沖擊也比較大,需謹(jǐn)慎使用饲宛。