SwiftUI-HealthKit中的DispatchQueue.main.async

SwiftUI-HealthKit中的DispatchQueue.main.async,swiftui,healthkit,Swiftui,Healthkit,我想在SwiftUI中加载以下GUI: import SwiftUI struct ContentView: View { @ObservedObject var test = Test() @ObservedObject var healthStore = HealthStore() func callUpdate() { print(test.value) print(healthSto

我想在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在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!)
    }
    
    
}
    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)")
    }

当我调用ContentView时,我需要如何修改代码以直接获得healthStore.systolicValue和healthStore.disatolicvalue的正确值?

我想你差不多做到了。您的HealthStore需要为发布新值 收缩值和舒张值。不需要“callUpdate()”函数

我将对您的代码进行如下修改:

(注意,一旦计算了systolicValue和DISATOLICVALUE,模型将更新,视图也将自动更新自身)

struct ContentView:View{
@ObservedObject变量healthStore=healthStore()
var body:一些观点{
VStack{
文本(“Platzhalter”)
文本(“systolicValue:\(healthStore.systolicValue)”)
文本(“舒张值:\(healthStore.diastolicValue)”)
}奥纳佩尔先生{
healthStore.setUpHealthStore()
}
}
}
类HealthStore:ObservableObject{
var healthStore:HKHealthStore?
var查询:HKStatisticsQuery?

@已发布的var systolicValue:HKQuantity?/@workingDog我按照建议更改了代码,但仍然无法从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()
            
        }
    }

您确定数据可用吗?要检查,请将其放入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!)
    }
    
    
}
    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()
        }
    }
}
这是我得到的输出:

-->请求授权

---->计算血压收缩统计:无

---->CalculateBloodPressureCystalError:可选(错误域=com.apple.healthkit Code=11“没有可用于指定谓词的数据。”UserInfo={NSLocalizedDescription=没有可用于指定谓词的数据。})

---->CalculateBloodPressureSytocol:可选(1.2())

---->计算血压舒张统计:无

---->CalculateBloodPressureDistributor错误:可选(错误域=com.apple.healthkit Code=11“指定谓词没有可用数据。”UserInfo={NSLocalizedDescription=指定谓词没有可用数据。})

---->计算血压舒张压:可选(3.4())

用户界面显示:

系统价值:1.2()

舒张值:3.4()

我发现了错误:

我在HealthStore类中声明变量systolicValue和DISATOLICVALUE是错误的。我将它们声明为public,而不是@Published。正确的代码是:

@Published var systolicValue: HKQuantity?
@Published var diastolicValue: HKQuantity?

谢谢您的帮助。

这是我的输出:-->CalculateBloodPressureStoryStorial statistics:Optional()------>CalculateBloodPressureStory错误:nil-->CalculateBloodPressureStoryStorial:Optional(1.2())很高兴听到您找到了原因。请将答案标记为正确,谢谢。