检查用户是否具有HealthKit中授权的步骤

时间:2018-11-08 08:13:56

标签: ios swift health-kit completionhandler

我试图弄清楚如何在completion内设置HKStatisticsCollectoniQuery块。

整个想法是因为我想知道用户是否已接受获取实例步骤的权限。但是根据Apple的文档,这是不可能的。

Apple authorizationStatus(for:)的文档

  

此方法检查授权状态以保存数据。   为帮助防止敏感健康信息的可能泄漏,您的应用无法确定用户是否已授予读取数据的权限。如果未获得您的许可,它看起来就像没有数据一样HealthKit存储中请求的类型。如果您的应用程序被授予共享权限,但没有读取权限,则您只会看到应用程序已写入商店的数据。来自其他来源的数据仍处于隐藏状态。


因此,我一直在考虑从2014年1月到今天的间隔时间。并查看该值是否仍为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 :(得分:1)

您有两种选择:使用跟踪异步操作的现有功能,或使用将为您完成操作的框架。第二种选择,我听说过有关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.
    }

答案 1 :(得分:1)

确定您的应用是否有权访问任何步骤的最有效方法是对限制为1且没有谓词或排序描述符的步骤执行单个HKSampleQuery。您无需在单独的时间段内执行多个查询。