我看到许多使用类成员变量将后台任务的值传递给完成块的示例:
self.bgTask = UIApplication.sharedApplication()
.beginBackgroundTaskWithName("bg task", expirationHandler: { () -> Void in
UIApplication.sharedApplication().endBackgroundTask(self.bgTask)
self.bgTask = UIBackgroundTaskInvalid
})
如果在第一个后台任务仍在运行时第二次调用此代码,则self.bgTask
将被新任务的标识符覆盖,UIApplication.sharedApplication().endBackgroundTask(self.bgTask)
可能永远不会被调用。
如果我声明了一个局部变量,那么在初始化之前它的值会被闭包捕获。也不好。
如何安全地将任务ID传递给完成处理程序?如果我的上述推理错误,请纠正我。
答案 0 :(得分:6)
在ObjC中,通常使用__block
变量来执行此操作,例如:
__block UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"Expired: %lu", (unsigned long)bgTask);
}];
NSLog(@"Background: %lu", (unsigned long)bgTask);
这会将bgTask
捕获为块的可变变量。复制块时,它会移动到堆中,并且局部变量bgTask
成为指向它的间接指针。请参阅Blocks Tips & Tricks中的bbum更广泛的解释。
如果您想将其分配给某个属性,那很好,但您并不需要。
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()
}
同样,除非您因某些其他原因需要,否则无需将值存储在属性中。该值作为局部变量存储在闭包内。
这是了解闭包的一个重要事项,是Swift的一个非常强大的功能。这可以让你这样做:
var n = 0
let nextNat = { n++ }
println(nextNat()) // => 0
println(nextNat()) // => 1
答案 1 :(得分:0)
你必须结束上一个任务并开始一个新任务 `
var uiBackgroundTaskIdentifier: UIBackgroundTaskIdentifier = UIBackgroundTaskIdentifier(rawValue: 0)
func beingOrEndBackgroundUpdateTask() {
DispatchQueue.main.async { [self] in
switch UIApplication.shared.applicationState {
case .background, .inactive:
beginBackgroundUpdateTask()
case .active:
endBackgroundUpdateTask()
default:
break
}
}
}
func beginBackgroundUpdateTask() {
// end previous task
endBackgroundUpdateTask()
self.uiBackgroundTaskIdentifier = UIApplication.shared.beginBackgroundTask (withName: "Finish Network Tasks") {
// End the task if time expires.
self.endBackgroundUpdateTask()
}
}
func endBackgroundUpdateTask() {
UIApplication.shared.endBackgroundTask(self.uiBackgroundTaskIdentifier)
self.uiBackgroundTaskIdentifier = UIBackgroundTaskIdentifier.invalid
}
`