Обработчик завершения возвращается до завершения задачи - PullRequest
2 голосов
/ 05 августа 2020

У меня есть эта функция, у которой есть обработчик завершения, который должен быть возвращен после завершения задачи, но из получаемых мной выходных данных он показывает, что обработчик завершения считается завершенным и возвращается до того, как задача будет выполнена.

Вызываемая функция:

private func getSteps(completion: (Int) -> ()) {
    var val: Int = 0
    guard let sampleType = HKObjectType.quantityType(forIdentifier: .stepCount) else { return }
    let startDate = Calendar.current.startOfDay(for: Date())
    let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictEndDate)
    var interval = DateComponents()
    
    interval.day = 1
    let query = HKStatisticsCollectionQuery(quantityType: sampleType, quantitySamplePredicate: predicate, options: [.cumulativeSum], anchorDate: startDate, intervalComponents: interval)
    query.initialResultsHandler = { query,result,error in
        if let myresult = result {
            myresult.enumerateStatistics(from: startDate, to: Date()) { (statistic, value) in
                if let count = statistic.sumQuantity() {
                    val = Int(count.doubleValue(for: HKUnit.count()))
                }
            }
        }
    }
    healthStore.execute(query)
    completion(val)
}

Когда я печатаю обработчик завершения функции, он печатает 0 вместо Int(count.doubleValue(for: HKUnit.count())), значение которого было установлено внутри функции. Мы будем очень благодарны за любые комментарии относительно того, почему я получаю 0 вместо установленного значения!

1 Ответ

3 голосов
/ 05 августа 2020

Обратите внимание, что query.initialResultsHandler - это асинхронный , и ваш код будет выполняться в следующем порядке:

private func getSteps(completion: (Int) -> ()) {
    // #1
    var val: Int = 0
    ...
    // #2
    query.initialResultsHandler = { query,result,error in
        // #5
        if let myresult = result {
            myresult.enumerateStatistics(from: startDate, to: Date()) { (statistic, value) in
                if let count = statistic.sumQuantity() {
                    // #6
                    val = Int(count.doubleValue(for: HKUnit.count()))
                }
            }
        }
        // #7
    }
    // #3
    healthStore.execute(query)
    // #4
    completion(val)
}

Обратите внимание, что # 4 выполняется перед # 6.

Решение - переместить completion внутрь асинхронного блока:

private func getSteps(completion: (Int) -> ()) {
    ...
    query.initialResultsHandler = { query,result,error in
        if let myresult = result {
            myresult.enumerateStatistics(from: startDate, to: Date()) { (statistic, value) in
                if let count = statistic.sumQuantity() {
                    val = Int(count.doubleValue(for: HKUnit.count()))
                }
            }
        }
        completion(val) // <- move here
    }
    healthStore.execute(query)
}
...