在Alamofire中使用backgroundCompletionHandler的正确方法是什么?

Pau*_*ung 6 nsurlsession nsurlsessionconfiguration alamofire

我不清楚如何正确使用它,但看到其他人做这种事情:

func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) {
    manager.sharedInstance.backgroundCompletionHandler = completionHandler
}
Run Code Online (Sandbox Code Playgroud)

在我们类似的实现中,此时completionHandlerpartial apply forwarder for reabstraction thunk helper...

在哪里manager(尽管是一个单身人士)基本上:

let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("com.ourcompany.app")
let manager = Alamofire.Manager(configuration: configuration)
Run Code Online (Sandbox Code Playgroud)

但是,这会导致在控制台中打印以下警告:

Warning: Application delegate received call to -application:handleEventsForBackgroundURLSession:completionHandler: but the completion handler was never called.

我设置一个断点位置,并在这一点上的消息已经是可见的控制台和backgroundCompletionHandlernil.

我们正在使用Xcode 7.0构建iOS 9 SDK,目前正在使用Alamofire 2.0.2

我最初认为这是在我们合并Swift 2.0分支时引入的,但是我也看到了使用Xcode 6.4对iOS 8 SDK的早期提交的消息.


更新1

要解决@ cnoon的建议:

  • 标识符匹配 - 配置和管理器设置在单例内,因此没有办法让它出错.
  • 在类中添加和打印内部时didSet,会backgroundCompletionHandler在警告之前Manager记录消息.
  • 当在封闭设置内部打印到类sessionDidFinishEventsForBackgroundURLSessiondelegate内部时Manager,在警告之后打印消息.
  • sessionDidFinishEventsForBackgroundURLSession在调用之前覆盖并打印内部时,会在警告backgroundCompletionHandler打印消息.
  • 至于验证我的Xcode项目是否正确设置为后台会话,我不知道该怎么做,也找不到任何关于如何做的文档.

我应该注意,当我尝试从手机上传一些屏幕截图时,我最初无法重现此问题以尝试这些建议.

只是在尝试分享一些照片之后,我才能再次重现这一点.我不确定或相关(如果有的话),但它可能与上传时间较长的照片有关.


更新2

所述UIBackgroundModes被设置完全一样@Nick所描述的,并调用completionHandler()直接的内部application:handleEventsForBackgroundURLSession:completionHandler:不显示警告.


更新3

所以,我似乎忽略了一个小而重要的细节.有一个包装器Alamofire.Manager,不会直接暴露它.其实施的相关部分如下所示:

private var manager: Manager

public var backgroundCompletionHandler: (() -> Void)? {
    get {
        return manager.backgroundCompletionHandler
    }
    set {
        manager.backgroundCompletionHandler = backgroundCompletionHandler
    }
}
Run Code Online (Sandbox Code Playgroud)

并在AppDelegate执行代码路径中设置完成处理程序.

func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) {
    myManager.sharedInstance.backgroundCompletionHandler = completionHandler
}
Run Code Online (Sandbox Code Playgroud)

我已经确认以下更改以公开实例Alamofire.Manager并直接访问它不会产生警告:

public var manager: Manager

//    public var backgroundCompletionHandler: (() -> Void)? {
//        get {
//            return manager.backgroundCompletionHandler
//        }
//        set {
//            manager.backgroundCompletionHandler = backgroundCompletionHandler
//        }
//    }
Run Code Online (Sandbox Code Playgroud)

并在AppDelegate:

func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) {
    myManager.sharedInstance.manager.backgroundCompletionHandler = completionHandler
}
Run Code Online (Sandbox Code Playgroud)

基于此,似乎使用计算属性来代理完成处理程序是问题的原因.

我真的不想暴露这个属性,并且想知道任何变通方法或替代方案.

cno*_*oon 1

看起来你所做的一切都是正确的。我有一个示例应用程序,它完全按照您所描述的方式工作,并且不会抛出您所看到的警告。我猜你在某个地方仍然有一些小错误。以下是一些可以尝试的想法:

  • 验证标识符与您的后台会话的标识符匹配
  • 临时在类中添加一条didSet日志语句以验证它是否已设置backgroundSessionHandlerManager
  • 添加一条日志语句以sessionDidFinishEventsForBackgroundURLSession验证它是否按预期被调用
  • 覆盖sessionDidFinishEventsForBackgroundURLSession委托上的 并手动调用backgroundSessionHandler
  • 验证您的 Xcode 项目是否已正确设置后台会话

更新2

您的计算属性是错误的。相反,它需要将设置backgroundCompletionHandlernewValue。否则你永远不会正确地将其设置为新值。请参阅此线程以获取更多信息。