【问题标题】:How to pass background task identifier to completion handler?如何将后台任务标识符传递给完成处理程序?
【发布时间】:2021-08-03 13:39:52
【问题描述】:

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

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

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    在 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
    

    【讨论】:

    • 啊...所以 Swift 不允许我在同一行的闭包中声明一个变量并绑定到它。在单独的行上声明 var bgTask: UIBackgroundTaskIdentifier = 0 会使编译器满意。
    • 正确。变量必须已经存在,闭包才能捕获它。
    【解决方案2】:

    你必须结束前一个任务并开始一个新任务 `

    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
    }
    

    `

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 2010-11-18
      • 1970-01-01
      • 2021-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多