如何将后台任务标识符传递给完成处理程序?

use*_*854 2 ios swift

我看到许多使用类成员变量将后台任务的值传递给完成块的示例:

self.bgTask = UIApplication.sharedApplication()
    .beginBackgroundTaskWithName("bg task", expirationHandler: { () -> Void in
        UIApplication.sharedApplication().endBackgroundTask(self.bgTask)
        self.bgTask = UIBackgroundTaskInvalid
        })
Run Code Online (Sandbox Code Playgroud)

如果在第一个后台任务仍在运行时第二次调用此代码,self.bgTask则会被新任务的标识符覆盖,并且UIApplication.sharedApplication().endBackgroundTask(self.bgTask)可能永远不会被调用.

如果我声明一个局部变量,那么它的值在被初始化之前被闭包捕获.也不好.

如何安全地将任务ID传递给完成处理程序?如果我的上述推理错误,请纠正我.

Rob*_*ier 6

在ObjC中,通常使用__block变量来执行此操作,例如:

__block UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        NSLog(@"Expired: %lu", (unsigned long)bgTask);
    }];
NSLog(@"Background: %lu", (unsigned long)bgTask);
Run Code Online (Sandbox Code Playgroud)

这捕获bgTask为块的可变变量.复制块时它会移动到堆中,并且局部变量bgTask是指向它的间接指针.请参阅bbum在Blocks Tips&Tricks中更广泛的解释.

如果你想将它分配给一个属性,那很好,但你不需要.

Swift没有__block属性,但它在没有任何帮助的情况下做了正确的事情.你只需要给它一个var工作.

func goBackground() {
    let app = UIApplication.sharedApplication()
    var bgTask: UIBackgroundTaskIdentifier = 0
    bgTask = app.beginBackgroundTaskWithExpirationHandler({
        NSLog("Expired: %lu", bgTask)
        app.endBackgroundTask(bgTask)
    })
    NSLog("Background: %lu", bgTask)
}

func applicationDidEnterBackground(application: UIApplication) {
    goBackground()
    goBackground()
}
Run Code Online (Sandbox Code Playgroud)

同样,没有必要将值存储在属性中,除非您出于某些其他原因需要它.该值作为局部变量存储在闭包内.

这是学习闭包的一个重要的事情,是Swift的一个非常强大的功能.这可以让你这样做:

var n = 0
let nextNat = { n++ }

println(nextNat()) // => 0
println(nextNat()) // => 1
Run Code Online (Sandbox Code Playgroud)