SwiftUI - HealthKit 中的 DispatchQueue.main.async
SwiftUI - DispatchQueue.main.async in HealthKit
我想在 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() 调用的。在第一次调用时,两个变量都为零。只有当我通过测试按钮调用函数时,控制台才会输出正确的值。
变量 healthStore.systolicValue 和 healthStore.diastolicValue 在 class 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 的正确值?
我想你快到了。您的 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? // <----
...
}
您确定数据可用吗?要检查一下,你能把这个放在 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)")
}
舒张压值也类似。
这是我用于测试并为我工作的完整代码,
使用 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 error: Optional(Error Domain=com.apple.healthkit Code=11 “没有可用于指定谓词的数据。”UserInfo={NSLocalizedDescription=没有可用于指定谓词的数据。} )
----> calculateBloodPressureSystolic: Optional(1.2 ())
----> 计算血压舒张压统计数据:无
----> calculateBloodPressureDiastolic error: Optional(Error Domain=com.apple.healthkit Code=11 “没有可用于指定谓词的数据。”UserInfo={NSLocalizedDescription=没有可用于指定谓词的数据。} )
----> calculateBloodPressureDiastolic: Optional(3.4())
并且 UI 显示:
收缩值:1.2 ()
舒张压值:3.4 ()
我发现了我的错误:
我在 class HealthStore 中声明变量 systolicValue 和 diastolicValue 是错误的。我将它们声明为 public 而不是 @Published。正确的代码是:
@Published var systolicValue: HKQuantity?
@Published var diastolicValue: HKQuantity?
谢谢你的帮助。
我想在 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() 调用的。在第一次调用时,两个变量都为零。只有当我通过测试按钮调用函数时,控制台才会输出正确的值。
变量 healthStore.systolicValue 和 healthStore.diastolicValue 在 class 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 的正确值?
我想你快到了。您的 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? // <----
...
}
您确定数据可用吗?要检查一下,你能把这个放在 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)")
}
舒张压值也类似。
这是我用于测试并为我工作的完整代码, 使用 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 error: Optional(Error Domain=com.apple.healthkit Code=11 “没有可用于指定谓词的数据。”UserInfo={NSLocalizedDescription=没有可用于指定谓词的数据。} )
----> calculateBloodPressureSystolic: Optional(1.2 ())
----> 计算血压舒张压统计数据:无
----> calculateBloodPressureDiastolic error: Optional(Error Domain=com.apple.healthkit Code=11 “没有可用于指定谓词的数据。”UserInfo={NSLocalizedDescription=没有可用于指定谓词的数据。} )
----> calculateBloodPressureDiastolic: Optional(3.4())
并且 UI 显示:
收缩值:1.2 ()
舒张压值:3.4 ()
我发现了我的错误:
我在 class HealthStore 中声明变量 systolicValue 和 diastolicValue 是错误的。我将它们声明为 public 而不是 @Published。正确的代码是:
@Published var systolicValue: HKQuantity?
@Published var diastolicValue: HKQuantity?
谢谢你的帮助。