Как использовать поток, который НЕ является основным, чтобы ждать, пока классическая переменная Bool не станет истинной? - PullRequest
1 голос
/ 30 марта 2019

Swift Новичок: я использую GCD через DispatchQueue.global (qos: .background) .async {code} для выполнения запросов HealthKit, прежде чем выполнять каждый запрос, который мне нужно подождать (реализованный с помощью цикла while / sleep) до появления класса static protectedDataEncrypted: Bool (который я использую для обозначения, если данные AppleHealth зашифрованы и недоступны), имеет значение false, я хочу убедиться, что GCD никогда не будет использовать поток Main (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, по-видимому, предотвращает зависание пользовательского интерфейса, тогда как, когда у меня был только Thread.sleep, иногда он зависал, если бы быстро блокировать / разблокировать экран непрерывно.

Пока что это работает, но я не уверен, что это будет работать 100% времени.

Большое спасибо заранее.

1 Ответ

2 голосов
/ 30 марта 2019

Во-первых, вам не нужны ваши 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.

...