Swift 如何使用不是主线程的线程来等待类静态Bool变量为true?

Swift 如何使用不是主线程的线程来等待类静态Bool变量为true?,swift,grand-central-dispatch,healthkit,ui-thread,hkhealthstore,Swift,Grand Central Dispatch,Healthkit,Ui Thread,Hkhealthstore,Swift新手:我正在通过DispatchQueue.global(qos:.background).async{code}使用GCD执行HealthKit查询,在执行每个查询之前,我需要等待(通过while/sleep循环实现),直到一个类static protectedDataEncrypted:Bool(我用来表示AppleHealth数据是否加密且不可访问)为false,我想确保GCD永远不会使用主(UI)线程检查/休眠静态protectedDataEncrypted:Bool,因为这将

Swift新手:我正在通过DispatchQueue.global(qos:.background).async{code}使用GCD执行HealthKit查询,在执行每个查询之前,我需要等待(通过while/sleep循环实现),直到一个类static protectedDataEncrypted:Bool(我用来表示AppleHealth数据是否加密且不可访问)为false,我想确保GCD永远不会使用主(UI)线程检查/休眠静态protectedDataEncrypted:Bool,因为这将冻结应用程序

到目前为止,我使用的方法是有效的,但我并不100%相信如果GCD出于某种原因使用主线程检查/休眠静态Bool,它不会死锁,根据我下面的代码,有什么方法比使用休眠更好

在AppDelegate中:我有以下内容:

static var protectedDataEncrypted = false

    override func applicationProtectedDataDidBecomeAvailable(_ application: UIApplication) {
        AppDelegate.protectedDataEncrypted = false
    }

    override func applicationProtectedDataWillBecomeUnavailable(_ application: UIApplication) {
        AppDelegate.protectedDataEncrypted = true
    }

在具有DispatchQueue.global(qos:.background).async{code}调用的方法的单独类中,我在执行HealthKit查询之前调用了以下方法

    func waitTillUnencrypted(){

        while (AppDelegate.protectedDataEncrypted){
                    DispatchQueue.global(qos: .background).sync {
                        Thread.sleep(forTimeInterval: 2)
                    }
        }
    }
注意:使用DispatchQueue.global(qos:.background).sync调用Thread.sleep似乎可以防止UI冻结,而当我只有Thread.sleep时,如果连续快速锁定/解锁屏幕,有时它会冻结

到目前为止,它是有效的,但我不相信它会100%的工作时间


非常感谢。

首先,您不需要自己的
protectedDataEncrypted
。这已经可以作为
UIApplication.shared.isProtectedDataAvailable
直接使用

您需要的是一个可以停止的队列。所以,创建一个队列来处理事情。如果受保护的数据不可用,请将其挂起

let protectedQueue = DispatchQueue(label: "protected")
if !UIApplication.shared.isProtectedDataAvailable {
    protectedQueue.suspend()
}
现在,使用
protectedQueue.dispatchAsync
放置在该队列上的任何内容都将在可能的情况下立即运行,或者在不可能的情况下排队

然后你可以像现在一样打开和关闭队列

override func applicationProtectedDataDidBecomeAvailable(_ application: UIApplication) {
    protectedQueue.resume()
}

override func applicationProtectedDataWillBecomeUnavailable(_ application: UIApplication) {
    protectedQueue.suspend()
}
尽管如此,通常更好的做法是构建您的操作,盲目地尝试自己执行,然后在错误失败时处理错误,而不是检查您是否认为它会成功。在某些竞争条件下,您可能会成功启动操作,但数据保护可能会在您完成之前启动。你必须处理那个案子。因为您必须处理这种情况,所以通常应该让该处理程序成为您处理无访问权限的方式

但在飞行前检查可能有用的情况下,或者如果它影响用户可见的元素,则上述检查可能有用


使用
sleep
进行轮询永远不是答案。即使您想要轮询(如果可能的话应该避免),也不应该使用
Thread.sleep
。这会束缚整个线程,并阻止其他任何东西使用它。如果您被迫这样做,轮询的方法是使用
dispatchAfter

重新安排您自己的时间,当从AppleHealth数据中回调表示加密已完成时,为什么要使用sleep方法?在回调中调用HealthKit查询??您可以使用NotificationCenter,而不是通过睡眠等待。在其他类中添加通知的观察者。从ApplicationProtectedData发送通知将变得不可用,并在该类中处理。感谢您给出的答案,感谢您提供的关于更好地轮询设计模式的提示。干杯