我试图弄清楚如何在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
}
}
如何确保完成块仅完成一次?
答案 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。您无需在单独的时间段内执行多个查询。