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

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

Спасибо заранее.


person Random Joe    schedule 30.03.2019    source источник
comment
Почему вы используете метод сна, когда есть обратный вызов из данных AppleHealth, который указывает, что шифрование выполнено? Вызвать запрос HealthKit в обратном вызове ??   -  person Mocha    schedule 30.03.2019
comment
Вместо ожидания в спящем режиме вы можете использовать NotificationCenter. Добавьте наблюдателя уведомления в какой-нибудь другой класс. Отправьте уведомление из applicationProtectedDataWillBecomeUnavailable и обработайте его в этом классе.   -  person Abhisheks    schedule 30.03.2019


Ответы (1)


Во-первых, нет необходимости в вашем собственном 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.

person Rob Napier    schedule 30.03.2019
comment
Оцените ответ, спасибо за советы по лучшему способу проведения опроса по шаблону дизайна, который вы обрисовали. Ваше здоровье - person Random Joe; 01.04.2019