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

时间:2015-03-11 17:39:50

标签: ios swift

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

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传递给完成处理程序?如果我的上述推理错误,请纠正我。

2 个答案:

答案 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
}

`