Проверьте, есть ли у пользователя авторизованные шаги в HealthKit - PullRequest
0 голосов
/ 08 ноября 2018

Я пытаюсь выяснить, как мне удается установить блок completion внутри HKStatisticsCollectoniQuery.

Вся идея в этом заключается в том, что я хочу знать, принял ли пользователь разрешения на выборку для шагов экземпляра. Но, согласно документации Apple, это невозможно.

Документация Apple для Состояние авторизации (для:)

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


Поэтому я думал о том, чтобы выбрать шаги между интервалами с января 2014 года до сегодняшнего дня. И посмотрите, равно ли это значение 0, что может означать две вещи. Или то, что пользователь не принял разрешение ... или что пользователь просто не прошел ни одного шага. Я не знаю, если это правильный подход. Так что, если есть лучший способ, я буду признателен за любой ответ!

Хорошо, пока я выполнил следующую функцию:

func retrieveTotalCount(typeIdentifier: HKQuantityTypeIdentifier, completion: @escaping (_ total: Double) -> Void) {
    //   Define the Step Quantity Type
    let unitsCount = HKQuantityType.quantityType(forIdentifier: typeIdentifier)!


    // "1391269654" stands for january 1st 2014
    let initialDate = Date(timeIntervalSince1970: Double(1391269654))

    //  Set the Predicates & Interval
    let predicate = HKQuery.predicateForSamples(withStart: initialDate, end: Date(), options: .strictStartDate)
    var interval = DateComponents()
    interval.day = 1

    //  Perform the Query
    let query = HKStatisticsCollectionQuery(quantityType: unitsCount, quantitySamplePredicate: predicate, options: [.cumulativeSum], anchorDate: initialDate as Date, intervalComponents:interval)

    query.initialResultsHandler = { query, results, error in
        if error != nil {
            //  Something went Wrong
            return
        }

        if let myResults = results { 
            myResults.enumerateStatistics(from: initialDate, to: Date()) { statistics, stop in

                if let quantity = statistics.sumQuantity() {
                    if quantity.is(compatibleWith: HKUnit.meter()) {
                        let count = quantity.doubleValue(for: HKUnit.meter())
                        completion(count)
                    } else if quantity.is(compatibleWith: HKUnit.kilocalorie()) {
                        let count = quantity.doubleValue(for: HKUnit.kilocalorie())
                        completion(count)
                    } else {
                        let count = quantity.doubleValue(for: HKUnit.count())
                        completion(count)
                    }
                }
            }
        }
    }
    self.healthStore.execute(query)
}

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

override func viewDidLoad() {
    super.viewDidLoad()

    var counter = 0
    HealthKitManager.shared.retrieveTotalCount(typeIdentifier: .stepCount) { (count) in
        counter += 1
        print("Counter: \(counter)")
        // In my case the Counter will print out:
        // Counter: 1
        // Counter: 2
        // Counter: ...
        // Counter: n
    }
}

Как я могу убедиться, что блок завершения был завершен только один раз?

Ответы [ 2 ]

0 голосов
/ 09 декабря 2018

Самый эффективный способ определить, имеет ли ваше приложение доступ к каким-либо шагам вообще, - выполнить один HKSampleQuery для шагов с пределом 1 и без дескрипторов предикатов или сортировки. Вам не нужно выполнять несколько запросов в разные периоды времени.

0 голосов
/ 08 декабря 2018

У вас есть два варианта: использовать существующую функцию, которая отслеживает асинхронные операции, или использовать среду, которая сделает это за вас. Что касается второго варианта, я слышал хорошие вещи о PromiseKit, но не использовал его.

В аналогичной ситуации я настроил DispatchQueue и использовал DispatchGroup для отслеживания завершения запросов:

let hkQueryGroup = DispatchGroup()
func runQuery (sampleType: HKQuantityType, start: Date, end: Date, name: String, quantityUnits: HKUnit) {
        hkQueryGroup.enter()
        let predicate = HKQuery.predicateForSamples(withStart: start, end: end, options: .strictStartDate)
        let query = HKStatisticsQuery(quantityType: sampleType,
                                      quantitySamplePredicate: predicate,
                                      options: .cumulativeSum)
        {_, result, error in
            if error != nil {
                // failure is still valid completion
                // do something with the data
                hkQueryGroup.leave()
                return
            }
            if let quantity = result?.sumQuantity()?.doubleValue(for: quantityUnits) {
                // do something with the data
            }
            else {
                //Returned *no* value for the quantity, which should not happen
            }
            hkQueryGroup.leave()
        }
        store.execute(query)
    }
    runQuery(sampleType: stepsType, start: startDate, end: endDate, name: "steps",quantityUnits: countUnit)
    runQuery(sampleType: distanceType, start: startDate, end: endDate, name: "distance",quantityUnits: distanceUnit)
    hkQueryGroup.notify(queue: DispatchQueue.main) {
        // do whatever you want when everything is finished)
        // to make sure all writes to the data dictionary have completed -- consider a barrier task in the queue.
    }
...