Проблема заключается в том, как дождаться, пока асинхронный запрос к HealthKit вернет результат ДО того, как выполнение будет продолжено. Возвращенные данные важны для дальнейшего выполнения.
Я знаю, что об этом спрашивали / решали много раз, и я прочитал много постов, однако я пробовал обработчики завершения, Диспетчерскую синхронизацию и Группы рассылки и не смог найти реализацию, которая работает.
Использование обработчика завершения
за Дождитесь завершения обработчика завершения - Swift
Вызывает метод для запуска запроса HealthKit:
func readHK() {
var block: Bool = false
hk.findLastBloodGlucoseInHealthKit(completion: { (result) -> Void in
block = true
if !(result) {
print("Problem with HK data")
}
else {
print ("Got HK data OK")
}
})
while !(block) {
}
// now move on to the next thing ...
}
Это работает. Использование переменной «block» для удержания выполнения в ожидании обратного вызова в концепции, похоже, не сильно отличается от блокировки семафоров, но это действительно уродливо и вызывает проблемы, если завершение не возвращается по какой-либо причине. Есть ли лучший способ?
Использование групп рассылки
Если я поместил Dispatch Group на уровень вызывающей функции:
Функция вызова:
func readHK() {
var block: Bool = false
dispatchGroup.enter()
hk.findLastBloodGlucoseInHealthKit(dg: dispatchGroup)
print ("Back from readHK")
dispatchGroup.notify(queue: .main) {
print("Function complete")
block = true
}
while !(block){
}
}
Функция получения:
func findLastBloodGlucoseInHealthKit(dg: DispatchGroup) {
print ("Read last HK glucose")
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
let query = HKSampleQuery(sampleType: glucoseQuantity!, predicate: nil, limit: 10, sortDescriptors: [sortDescriptor]) { (query, results, error) in
// .... other stuff
dg.leave()
Завершение выполняется ОК, но метод .notify никогда не вызывается, поэтому переменная блока никогда не обновляется, программа зависает и никогда не выходит из оператора while.
Поместить группу отправки в целевую функцию, но оставить .notify на уровне вызова:
func readHK() {
var done: Bool = false
hk.findLastBloodGlucoseInHealthKit()
print ("Back from readHK")
hk.dispatchGroup.notify(queue: .main) {
print("done function")
done = true
}
while !(done) {
}
}
Та же проблема.
Использование диспетчеризации
Документация и другие сообщения S.O говорят: «Если вы хотите дождаться завершения блока, используйте вместо этого метод sync ()».
Но что значит «завершить»? Кажется, что это не значит завершить функцию и получить последующее асинхронное завершение. Например, нижеприведенное не удерживает выполнение до тех пор, пока не завершится возврат:
func readHK() {
DispatchQueue.global(qos: .background).sync {
hk.findLastBloodGlucoseInHealthKit()
}
print ("Back from readHK")
}
Спасибо за любую помощь.