在后台下载期间不会调用我的NSURLSessionDelegate方法

jjo*_*son 9 cocoa-touch objective-c ios ios7 nsurlsession

我正在尝试设置下载使用NSURLSession它将在后台继续.我有一个单独的类DownloadManager,它构建NSURLSession并启动下载任务,如下所示:

- (id)init
{
    self = [super init];
    if (self) {
        self.queue = [[NSOperationQueue alloc] init];
        self.queue.maxConcurrentOperationCount = 1;

        // Initialize the background session.
        self.session = [self backgroundSession];
    }
    return self;
}

- (NSURLSession *)backgroundSession
{
    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.mycompany.myapp.BackgroundSession"];
        session = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                delegate:self
                                           delegateQueue:self.queue];
    });
    return session;
}

- (void)startDownload:(Download *)download
{
    NSURL *remoteURL = ...
    NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:remoteURL];
    [task resume];
}
Run Code Online (Sandbox Code Playgroud)

我已经实现了包括的方法NSURLSessionDelegateNSURLSessionDownloadDelegate方法URLSessionDidFinishEventsForBackgroundURLSession:.另外,我的应用程序委托实现application:handleEventsForBackgroundURLSession:completionHandler:.

但是,当我在开始下载后按下主页按钮将我的应用程序移动到后台时,所有下载委托方法都会停止触发并且application:handleEventsForBackgroundURLSession:completionHandler:永远不会被调用.下载继续,如果我等待足够长时间完成,那么URLSession:downloadTask:didFinishDownloadingToURL:我将应用程序带回前台的那一刻就会被调用.这意味着我无法在后台进行任何后期处理(例如保存到核心数据,开始新的下载等).

我尝试将"后台获取"后台模式添加到我的plist,以防需要,我尝试更改用于创建NSURLSessionConfiguration后台配置的标识符,如本答案中所建议的那样.我在设置时犯了错误,还是我不能在后台处理下载委托事件?

Rob*_*Rob 9

在单个下载在后台完成时,您不会看到调用的下载委托事件,而是仅在重新启动应用程序后才会看到.例如,当所有下载成功完成(handleEventsForBackgroundURLSession调用时)或手动重启应用程序时.

至于为什么你没有看到handleEventsForBackgroundURLSession被叫,我只能想到一对(不可否认,不太可能)的可能性:

  1. 确保handleEventsForBackgroundURLSession应用程序委托中的签名绝对正确(大小写,拼写等).一个小错字不会产生任何警告,但它会导致它不被调用.所以它应该是:

    - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
    {
        // save the completionHandler here
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您确定所有后台下载都已完成吗?如果其中一个由于某种原因挂起或失败,那将阻止触发后台会话的完成,并且因为仅在完成所有操作时调用委托方法,这意味着您的应用程序将不会被激活.我建议仔细检查所有下载是否已完成.

  3. 你检查过设备的控制台了吗?(如果您转到Xcode"Organizer"的"Devices"部分,您可以看到这一点.)有时会有一些有趣的诊断错误消息,后台守护程序会为您记录.如果你还没有检查出来.那里有很多有趣的东西.

  4. 如果您通过SpringBoard手动终止应用程序(双击物理主页按钮,按住应用程序图标直到其摇晃,单击红色"x"),这将终止后台下载任务,因此您将不会收到所有通知下载完成了.确保您实施,URLSession:task:didCompleteWithError:以便您可以看到此错误(和任何其他错误).

    但是,如果我按照WWDC 2013视频中的说明以编程方式使应用程序崩溃,那么基础网络中有什么新功能,或者系统是否终止,则后台下载正确完成,并且正确调用应用程序委托方法.

只需要考虑一些想法.

  • 我有同样的问题,甚至使用Apple的示例代码(https://developer.apple.com/library/ios/samplecode/SimpleBackgroundTransfer/Introduction/Intro.html#//apple_ref/doc/uid/DTS40013416)我可以不要让AppDelegate方法被调用. (2认同)