Swift: публикация данных из одного класса в другой не работает (Apple HealthKit)

сорт

      import Foundation
import HealthKit

class HealthKitQueryBuilder:ObservableObject {
    
    let healthStore: HKHealthStore
    let dateFormatter = DateFormatter()
    
    @Published var hourlyStpCount: [HealthData]?
    
    init(healthStore: HKHealthStore) {
        self.healthStore = healthStore
    }

func readHourlyStepCount(){
        dateFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss"
        var hourlyStepCount = [HealthData]()
        guard let stepCountType = HKObjectType.quantityType(forIdentifier: .stepCount) else {
            fatalError("*** Unable to get the step count type ***")
        }

        var interval = DateComponents()
        interval.hour = 1

        let calendar = Calendar.current
        let anchorDate = calendar.date(bySettingHour: 0, minute: 55, second: 0, of: Date())

        let query = HKStatisticsCollectionQuery.init(quantityType: stepCountType,
                                                     quantitySamplePredicate: nil,
                                                     options: .cumulativeSum,
                                                     anchorDate: anchorDate!,
                                                     intervalComponents: interval)

        query.initialResultsHandler = { query, results, error in
            let startDate = calendar.date(byAdding: .hour,value: -24, to: Date())
            DispatchQueue.main.async {
            results?.enumerateStatistics(from: startDate!,to: Date(), with: { (result, stop) in

                    hourlyStepCount.append(HealthData(unit: "count", startDate: self.dateFormatter.string(from: result.startDate) , endDate: self.dateFormatter.string(from: result.endDate), value: (result.sumQuantity()?.doubleValue(for: HKUnit.count()) ?? 0)))


            })
                print("Hourly step count : \(hourlyStepCount)")
                self.hourlyStpCount = hourlyStepCount
            }

        }
healthStore.execute(query)
}
}

сорт

      import Foundation
import HealthKit
import SwiftUI

class DataPointsJSONBuilder {
    
    let healthStore: HKHealthStore
    @ObservedObject var queryBuilder: HealthKitQueryBuilder
    
    init(healthStore: HKHealthStore) {
        self.healthStore = healthStore
        self.queryBuilder = HealthKitQueryBuilder(healthStore: healthStore)
    }
    
    func createJSON() ->String?{
        queryBuilder.readHourlyStepCount()
        let totalStepCount = queryBuilder.hourlyStpCount
        let averageRestingHeartRate = [HealthData(unit: "count", startDate: "2022-11-22 10:55:00 PM +0000", endDate: "2022-11-22 11:55:00 PM +0000", value: 100.0)]
        let averageHeartRateVariability = [HealthData(unit: "count", startDate: "2022-11-22 10:55:00 PM +0000", endDate: "2022-11-22 11:55:00 PM +0000", value: 100.0)]
        let averageRespiratoryRate = [HealthData(unit: "count", startDate: "2022-11-22 10:55:00 PM +0000", endDate: "2022-11-22 11:55:00 PM +0000", value: 100.0)]
        let totalSleepDuration = [HealthData(unit: "count", startDate: "2022-11-22 10:55:00 PM +0000", endDate: "2022-11-22 11:55:00 PM +0000", value: 100.0)]
        let heartRate = [HealthData(unit: "count", startDate: "2022-11-22 10:55:00 PM +0000", endDate: "2022-11-22 11:55:00 PM +0000", value: 100.0)]
        let systolicBloodPressure = [HealthData(unit: "count", startDate: "2022-11-22 10:55:00 PM +0000", endDate: "2022-11-22 11:55:00 PM +0000", value: 100.0)]
        let diastolicBloodPressure = [HealthData(unit: "count", startDate: "2022-11-22 10:55:00 PM +0000", endDate: "2022-11-22 11:55:00 PM +0000", value: 100.0)]
        let oxygenSaturation = [HealthData(unit: "count", startDate: "2022-11-22 10:55:00 PM +0000", endDate: "2022-11-22 11:55:00 PM +0000", value: 100.0)]
        let currentGlucose = [HealthData(unit: "count", startDate: "2022-11-22 10:55:00 PM +0000", endDate: "2022-11-22 11:55:00 PM +0000", value: 100.0)]
        let averageGlucose = [HealthData(unit: "count", startDate: "2022-11-22 10:55:00 PM +0000", endDate: "2022-11-22 11:55:00 PM +0000", value: 100.0)]
        
        let dataPoints = DataPointsObj(totalStepCount: totalStepCount, averageRestingHeartRate: [], averaHeartRatevariability: [], averageRespiratoryRate: [], totalSleepDuration: [], heartRate: [], systolicBloodPressure: [], diastolicBloodPressure: [], oxygenSaturation: [], currentGlucoseValue: [], averageGlucoseValue: [])
        
        guard let JSON = encodeToJSON(dataPointsObj: dataPoints) else {
            return nil
        }
        return JSON
    }
    
    private func encodeToJSON(dataPointsObj: DataPointsObj) -> String? {
        let encoder = JSONEncoder()
        encoder.outputFormatting = .withoutEscapingSlashes
        do {
            let result = try encoder.encode(dataPointsObj)
            if let jsonString = String(data: result, encoding: .utf8){
                return jsonString
            }
            return nil
        } catch {
            return nil
        }
    }
}

У меня есть выше 2 классов, реализованных для чтения данных из набора здоровья Apple и создания объекта json для отправки его на серверную часть. Но после извлечения данных данные не публикуются в классе. Я печатаю данные внутриHealthKitQueryBuilderclass успешно, и я добавил код для подсчета шагов только на данный момент. я звонюcreateJSONфункция внутриonAppearв пользовательском интерфейсе следующим образом.

      .onAppear(){

print(DataPointsJSONBuilder(healthStore: healthStore).createJSON()!)

}

Что я хочу сделать, так это прочитать данные из HealthKit и перенести их вDataPointsJSONBuilderкласс, чтобы отправить его на серверную часть через REST API. Я не понимаю, почему я hourlyStpCount не обновляется при чтении данных. Если здесь есть неправильная реализация, поправьте меня или предложите способ решения моей проблемы. Спасибо!

1 ответ

Я бы сказал, что проблема здесь в том, что вы пытаетесь использовать асинхронный вызов как синхронный.

Ты используешь

       print(DataPointsJSONBuilder(healthStore: healthStore).createJSON()!)

Функция createJSON() имеет возврат. Вместо этого он должен иметь асинхронный подход. Есть много способов реализовать это — вы пытались использовать один из них, например, функциональность @Published — но для простоты я публикую способ, используя обратные вызовы (обработчики завершения).

Вам нужно будет изменить относительно большой кусок кода, но, чтобы подчеркнуть мою точку зрения, в конце он должен быть примерно таким:

      func readHourlyStepCount(callback: ([HealthData]) -> ()) {
//implementation
   callback(hourlyStepCount)
//...
}

В DataPointsJSONBuilder:

      func createJSON(callback: (String?) -> ()) {
//implementation
   callback(JSON)
//...
}

И наконец:

      DataPointsJSONBuilder(healthStore: healthStore).createJSON { json in
   print(json)
}

PS: Возможно, вам нужно добавить тег @escaping в обратные вызовы.

Другие вопросы по тегам