3 回答

TA貢獻1803條經驗 獲得超6個贊
一些想法:
您必須確保執行“ URL加載系統編程指南”的“ 處理iOS后臺活動”部分中概述的必要編碼:
如果您NSURLSession在iOS 中使用,則下載完成后會自動重新啟動您的應用。應用程序的application:handleEventsForBackgroundURLSession:completionHandler:應用程序委托方法負責重新創建適當的會話,存儲完成處理程序,并在會話調用您的會話委托人的URLSessionDidFinishEventsForBackgroundURLSession:方法時調用該處理程序。
該指南顯示了您可以執行的一些示例。坦率地說,我覺得在WWDC 2013視頻的后半部分討論的代碼樣本中的新增基礎網絡都顯得更加清晰。
AFURLSessionManager如果僅暫停了應用程序,則的基本實現將與后臺會話配合使用(假設您已完成上述操作,則在完成網絡任務時,您會看到調用的塊)。但是,正如您猜到的那樣,“如果應用終止或崩潰” ,傳遞給AFURLSessionManager您創建NSURLSessionTask用于上載和下載的方法的特定于任務的塊參數都將丟失。
對于后臺上傳,這很煩人(因為在創建任務時指定的任務級信息進度和完成塊將不會被調用)。但是,如果您使用會話級再現(例如setTaskDidCompleteBlock和setTaskDidSendBodyDataBlock),則會被正確調用(假設在重新實例化會話管理器時始終設置這些塊)。
事實證明,丟失塊的問題實際上對于后臺下載而言更成問題,但是那里的解決方案非常相似(不要使用基于任務的塊參數,而要使用基于會話的塊,例如setDownloadTaskDidFinishDownloadingBlock)。
另一種選擇是,您可以使用默認設置(非后臺)NSURLSession,但是如果用戶在執行任務時離開應用程序,請確保您的應用程序請求一點時間來完成上傳。例如,在創建之前NSURLSessionTask,您可以創建一個UIBackgroundTaskIdentifier:
UIBackgroundTaskIdentifier __block taskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^(void) {
// handle timeout gracefully if you can
[[UIApplication sharedApplication] endBackgroundTask:taskId];
taskId = UIBackgroundTaskInvalid;
}];
但是,請確保網絡任務的完成塊正確通知iOS它已完成:
if (taskId != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:taskId];
taskId = UIBackgroundTaskInvalid;
}
這沒有背景那么強大NSURLSession(例如,您有有限的可用時間),但是在某些情況下這可能很有用。
更新:
我以為我會添加一個實際的示例,說明如何使用AFNetworking進行后臺下載。
首先定義您的后臺經理。
//
// BackgroundSessionManager.h
//
// Created by Robert Ryan on 10/11/14.
// Copyright (c) 2014 Robert Ryan. All rights reserved.
//
#import "AFHTTPSessionManager.h"
@interface BackgroundSessionManager : AFHTTPSessionManager
+ (instancetype)sharedManager;
@property (nonatomic, copy) void (^savedCompletionHandler)(void);
@end
和
//
// BackgroundSessionManager.m
//
// Created by Robert Ryan on 10/11/14.
// Copyright (c) 2014 Robert Ryan. All rights reserved.
//
#import "BackgroundSessionManager.h"
static NSString * const kBackgroundSessionIdentifier = @"com.domain.backgroundsession";
@implementation BackgroundSessionManager
+ (instancetype)sharedManager {
static id sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (instancetype)init {
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:kBackgroundSessionIdentifier];
self = [super initWithSessionConfiguration:configuration];
if (self) {
[self configureDownloadFinished]; // when download done, save file
[self configureBackgroundSessionFinished]; // when entire background session done, call completion handler
[self configureAuthentication]; // my server uses authentication, so let's handle that; if you don't use authentication challenges, you can remove this
}
return self;
}
- (void)configureDownloadFinished {
// just save the downloaded file to documents folder using filename from URL
[self setDownloadTaskDidFinishDownloadingBlock:^NSURL *(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location) {
if ([downloadTask.response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = [(NSHTTPURLResponse *)downloadTask.response statusCode];
if (statusCode != 200) {
// handle error here, e.g.
NSLog(@"%@ failed (statusCode = %ld)", [downloadTask.originalRequest.URL lastPathComponent], statusCode);
return nil;
}
}
NSString *filename = [downloadTask.originalRequest.URL lastPathComponent];
NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *path = [documentsPath stringByAppendingPathComponent:filename];
return [NSURL fileURLWithPath:path];
}];
[self setTaskDidCompleteBlock:^(NSURLSession *session, NSURLSessionTask *task, NSError *error) {
if (error) {
// handle error here, e.g.,
NSLog(@"%@: %@", [task.originalRequest.URL lastPathComponent], error);
}
}];
}
- (void)configureBackgroundSessionFinished {
typeof(self) __weak weakSelf = self;
[self setDidFinishEventsForBackgroundURLSessionBlock:^(NSURLSession *session) {
if (weakSelf.savedCompletionHandler) {
weakSelf.savedCompletionHandler();
weakSelf.savedCompletionHandler = nil;
}
}];
}
- (void)configureAuthentication {
NSURLCredential *myCredential = [NSURLCredential credentialWithUser:@"userid" password:@"password" persistence:NSURLCredentialPersistenceForSession];
[self setTaskDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *credential) {
if (challenge.previousFailureCount == 0) {
*credential = myCredential;
return NSURLSessionAuthChallengeUseCredential;
} else {
return NSURLSessionAuthChallengePerformDefaultHandling;
}
}];
}
@end
確保應用程序委托保存完成處理程序(根據需要實例化后臺會話):
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
NSAssert([[BackgroundSessionManager sharedManager].session.configuration.identifier isEqualToString:identifier], @"Identifiers didn't match");
[BackgroundSessionManager sharedManager].savedCompletionHandler = completionHandler;
}
然后開始下載:
for (NSString *filename in filenames) {
NSURL *url = [baseURL URLByAppendingPathComponent:filename];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[[[BackgroundSessionManager sharedManager] downloadTaskWithRequest:request progress:nil destination:nil completionHandler:nil] resume];
}
請注意,我不提供任何與任務相關的塊,因為它們與后臺會話不可靠。(即使在應用終止后,背景下載仍會繼續進行,并且這些功能塊早已消失。)人們必須依靠會話級別,并且setDownloadTaskDidFinishDownloadingBlock只能輕松地重新創建。
顯然,這是一個簡單的示例(僅一個后臺會話對象;僅使用URL的最后一個組件作為文件名將文件保存到docs文件夾中;等等),但希望它能說明這種模式。

TA貢獻2021條經驗 獲得超8個贊
回調是否為塊應該沒有任何區別。實例化an時AFURLSessionManager
,請確保使用實例化它NSURLSessionConfiguration backgroundSessionConfiguration:
。此外,請確保調用經理setDidFinishEventsForBackgroundURLSessionBlock
與你的回調塊-這就是你應該寫通常NSURLSessionDelegate的方法定義的代碼: URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
。此代碼應調用您的應用程序委托的后臺下載完成處理程序。
關于后臺下載任務的一則建議-即使在前臺運行時,它們的超時也將被忽略,這意味著您可能會在沒有響應的下載中“卡住”。這沒有記錄在任何地方,使我瘋了一段時間。第一個嫌疑人是AFNetworking,但即使直接調用NSURLSession之后,其行為也保持不變。
祝好運!

TA貢獻1804條經驗 獲得超3個贊
AFURLSessionManager
AFURLSessionManager創建和管理的NSURLSession基于指定的對象上NSURLSessionConfiguration的對象,它符合<NSURLSessionTaskDelegate>,<NSURLSessionDataDelegate>,<NSURLSessionDownloadDelegate>,和<NSURLSessionDelegate>。
鏈接到此處的文檔
- 3 回答
- 0 關注
- 907 瀏覽
添加回答
舉報