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 для отправки его на серверную часть. Но после извлечения данных данные не публикуются в классе. Я печатаю данные внутриHealthKitQueryBuilder
class успешно, и я добавил код для подсчета шагов только на данный момент. я звоню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 в обратные вызовы.