SwiftUI - HealthKit 中的 DispatchQueue.main.async
Posted
技术标签:
【中文标题】SwiftUI - HealthKit 中的 DispatchQueue.main.async【英文标题】:SwiftUI - DispatchQueue.main.async in HealthKit 【发布时间】:2021-05-24 09:46:37 【问题描述】:我想在 SwiftUI 中加载以下 GUI:
import SwiftUI
struct ContentView: View
@ObservedObject var test = Test()
@ObservedObject var healthStore = HealthStore()
func callUpdate()
print(test.value)
print(healthStore.systolicValue)
print(healthStore.diastolicValue)
var body: some View
Text("Platzhalter")
.padding()
.onAppear(perform:
healthStore.setUpHealthStore()
callUpdate()
)
Button("Test")
callUpdate()
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
变量 healthStore.systolicValue 和 healthStore.diastolicValue 是通过函数 callUpdate() 调用的。在第一次调用时,两个变量都为零。只有当我通过Test按钮调用该函数时,才会在控制台中输出正确的值。
变量 healthStore.systolicValue 和 healthStore.diastolicValue 在 HealthStore 类中计算:
import Foundation
import HealthKit
class HealthStore: ObservableObject
var healthStore: HKHealthStore?
var query: HKStatisticsQuery?
public var systolicValue: HKQuantity?
public var diastolicValue: HKQuantity?
init()
if HKHealthStore.isHealthDataAvailable()
healthStore = HKHealthStore()
func setUpHealthStore()
let typesToRead: Set = [
HKQuantityType.quantityType(forIdentifier: .bloodPressureSystolic)!,
HKQuantityType.quantityType(forIdentifier: .bloodPressureDiastolic)!
]
healthStore?.requestAuthorization(toShare: nil, read: typesToRead, completion: success, error in
if success
print("requestAuthrization")
self.calculateBloodPressureSystolic()
self.calculateBloodPressureDiastolic()
)
func calculateBloodPressureSystolic()
guard let bloodPressureSystolic = HKObjectType.quantityType(forIdentifier: .bloodPressureSystolic) else
// This should never fail when using a defined constant.
fatalError("*** Unable to get the bloodPressure count ***")
query = HKStatisticsQuery(quantityType: bloodPressureSystolic,
quantitySamplePredicate: nil,
options: .discreteAverage)
query, statistics, error in
DispatchQueue.main.async
self.systolicValue = statistics?.averageQuantity()
healthStore!.execute(query!)
func calculateBloodPressureDiastolic()
guard let bloodPressureDiastolic = HKObjectType.quantityType(forIdentifier: .bloodPressureDiastolic) else
// This should never fail when using a defined constant.
fatalError("*** Unable to get the bloodPressure count ***")
query = HKStatisticsQuery(quantityType: bloodPressureDiastolic,
quantitySamplePredicate: nil,
options: .discreteAverage)
query, statistics, error in
DispatchQueue.main.async
self.diastolicValue = statistics?.averageQuantity()
healthStore!.execute(query!)
当我调用 ContentView 时,如何修改我的代码以直接获取 healthStore.systolicValue 和 healthStore.diastolicValue 的正确值?
【问题讨论】:
【参考方案1】:这是我用于测试并为我工作的完整代码, 使用 macos 11.4,xcode 12.5,目标 ios 14.5,在 iPhone 设备上测试。 如果这对您不起作用,请告诉我们。
import SwiftUI
import HealthKit
@main
struct TestErrorApp: App
var body: some Scene
WindowGroup
ContentView()
class HealthStore: ObservableObject
var healthStore: HKHealthStore?
var query: HKStatisticsQuery?
@Published var systolicValue: HKQuantity?
@Published var diastolicValue: HKQuantity?
init()
if HKHealthStore.isHealthDataAvailable()
healthStore = HKHealthStore()
func setUpHealthStore()
let typesToRead: Set = [
HKQuantityType.quantityType(forIdentifier: .bloodPressureSystolic)!,
HKQuantityType.quantityType(forIdentifier: .bloodPressureDiastolic)!
]
healthStore?.requestAuthorization(toShare: nil, read: typesToRead, completion: success, error in
if success
print("--> requestAuthorization")
self.calculateBloodPressureSystolic()
self.calculateBloodPressureDiastolic()
)
func calculateBloodPressureSystolic()
guard let bloodPressureSystolic = HKObjectType.quantityType(forIdentifier: .bloodPressureSystolic) else
// This should never fail when using a defined constant.
fatalError("*** Unable to get the bloodPressure count ***")
query = HKStatisticsQuery(quantityType: bloodPressureSystolic,
quantitySamplePredicate: nil,
options: .discreteAverage)
query, statistics, error in
DispatchQueue.main.async
// self.systolicValue = statistics?.averageQuantity()
self.systolicValue = HKQuantity(unit: HKUnit(from: ""), doubleValue: 1.2)
print("----> calculateBloodPressureSystolic statistics: \(statistics)")
print("----> calculateBloodPressureSystolic error: \(error)")
print("----> calculateBloodPressureSystolic: \(self.systolicValue)")
healthStore!.execute(query!)
func calculateBloodPressureDiastolic()
guard let bloodPressureDiastolic = HKObjectType.quantityType(forIdentifier: .bloodPressureDiastolic) else
// This should never fail when using a defined constant.
fatalError("*** Unable to get the bloodPressure count ***")
query = HKStatisticsQuery(quantityType: bloodPressureDiastolic,
quantitySamplePredicate: nil,
options: .discreteAverage)
query, statistics, error in
DispatchQueue.main.async
// self.diastolicValue = statistics?.averageQuantity()
self.diastolicValue = HKQuantity(unit: HKUnit(from: ""), doubleValue: 3.4)
print("----> calculateBloodPressureDiastolic statistics: \(statistics)")
print("----> calculateBloodPressureDiastolic error: \(error)")
print("----> calculateBloodPressureDiastolic: \(self.diastolicValue)")
healthStore!.execute(query!)
struct ContentView: View
@ObservedObject var healthStore = HealthStore()
var bloodPressureStandard = HKQuantity(unit: HKUnit(from: ""), doubleValue: 0.0)
var body: some View
VStack
Text("systolicValue: \(healthStore.systolicValue ?? bloodPressureStandard)")
Text("diastolicValue: \(healthStore.diastolicValue ?? bloodPressureStandard)")
.onAppear
healthStore.setUpHealthStore()
这是我得到的输出:
--> 请求授权
----> 计算血压收缩统计:无
----> calculateBloodPressureSystolic 错误:可选(错误域=com.apple.healthkit 代码=11“指定谓词没有可用数据。” UserInfo=NSLocalizedDescription=指定谓词没有可用数据。)
----> 计算血压收缩压:可选(1.2())
----> 计算血压舒张压统计:无
----> calculateBloodPressureDiastolic 错误:可选(错误域=com.apple.healthkit Code=11“指定谓词没有可用数据。” UserInfo=NSLocalizedDescription=指定谓词没有可用数据。)
---->calculateBloodPressureDiastolic:可选(3.4())
UI 显示:
收缩值:1.2 ()
舒张压值:3.4 ()
【讨论】:
【参考方案2】:我想你快到了。您的 HealthStore 需要为 收缩值和舒张值。不需要“callUpdate()”函数。
我会修改你的代码如下:
(注意一旦计算出 systolicValue 和 diastolicValue,模型会更新,视图也会自动更新)
struct ContentView: View
@ObservedObject var healthStore = HealthStore()
var body: some View
VStack
Text("Platzhalter")
Text("systolicValue: \(healthStore.systolicValue)")
Text("diastolicValue: \(healthStore.diastolicValue)")
.onAppear
healthStore.setUpHealthStore()
class HealthStore: ObservableObject
var healthStore: HKHealthStore?
var query: HKStatisticsQuery?
@Published var systolicValue: HKQuantity? // <----
@Published var diastolicValue: HKQuantity? // <----
...
【讨论】:
【参考方案3】:@workindog 我按照建议更改了我的代码,但我仍然没有从 healthStore 获得计算值。
@ObservedObject var healthStore = HealthStore()
var bloodPressureStandard = HKQuantity(unit: HKUnit(from: ""), doubleValue: 0.0)
var body: some View
VStack
Text("systolicValue: \(healthStore.systolicValue ?? bloodPressureStandard)")
Text("diastolicValue: \(healthStore.diastolicValue ?? bloodPressureStandard)")
.onAppear
healthStore.setUpHealthStore()
【讨论】:
【参考方案4】:您确定数据可用吗?要检查,你能把它放在 HealthStore 中吗:
DispatchQueue.main.async
// self.systolicValue = statistics?.averageQuantity()
self.systolicValue = HKQuantity(unit: HKUnit(from: ""), doubleValue: 1.2)
print("----> calculateBloodPressureSystolic statistics: \(statistics)")
print("----> calculateBloodPressureSystolic error: \(error)")
print("----> calculateBloodPressureSystolic: \(self.systolicValue)")
diastolicValue 也是如此。
【讨论】:
这是我的输出:----> calculateBloodPressureSystolic 统计:可选( HKQuantityTypeIdentifierBloodPressureSystolic 的统计(2021-05-05 19:17:00 +0000 - 2021-05- 05 21:59:00 +0000) 过源 ((null))>) ----> calculateBloodPressureSystolic 错误:nil ----> calculateBloodPressureSystolic:可选(1.2())【参考方案5】:我发现了我的错误:
我在 HealthStore 类中声明了变量 systolicValue 和 diastolicValue 错误。我将它们声明为公共而不是@Published。正确的代码是:
@Published var systolicValue: HKQuantity?
@Published var diastolicValue: HKQuantity?
感谢您的帮助。
【讨论】:
很高兴听到您找到了原因。请把答案标记为正确,谢谢。以上是关于SwiftUI - HealthKit 中的 DispatchQueue.main.async的主要内容,如果未能解决你的问题,请参考以下文章