Ios 在触发我的完成处理程序之前,如何最好地确保我拥有所有数据?
我不知道如何最好地获取我的健康工具包数据,特别是心率记录。我的问题是由于竞争条件(这是由于异步调用)和完成处理程序引起的 我的应用程序记录了一次训练,并最终将数据推送到远程服务器进行清理、分析。我想在会话同步请求中包含心率数据 会话由GPS和其他传感器数据组成,这些数据分为几圈 当我开始同步会话时,我会这样调用以下函数:Ios 在触发我的完成处理程序之前,如何最好地确保我拥有所有数据?,ios,swift,Ios,Swift,我不知道如何最好地获取我的健康工具包数据,特别是心率记录。我的问题是由于竞争条件(这是由于异步调用)和完成处理程序引起的 我的应用程序记录了一次训练,并最终将数据推送到远程服务器进行清理、分析。我想在会话同步请求中包含心率数据 会话由GPS和其他传感器数据组成,这些数据分为几圈 当我开始同步会话时,我会这样调用以下函数: fetchSessionLapTimes(session: session) { (storedSessionLapTime, error) in //handle t
fetchSessionLapTimes(session: session) { (storedSessionLapTime, error) in
//handle the received lap time data
//At this point, I expect my storedSessionLapTime variable to
//contain my session lap times, and heart rate data
})
MyfetchSessionLapTimes
函数的定义如下:
func fetchSessionLapTimes(session: Session, withCompletion complete: ((_ storedSessionLapTime: [SessionLapTime], _ error: Error?) -> Void)!) {
var storedSessionLapTime = [SessionLapTime]()
managedObjectContext.performAndWait {
//get session lap times from Core Data
//this code works fine, as expected and populates
//storedSessionLapTime
}
//now this is where my problem is. At this point I want to extract
//heart rate data for each lap time
let healthStoreService = HealthStoreService()
for sessionLapTime in storedSessionLapTime {
let start = Date(timeIntervalSince1970: sessionLapTime.lapStartDate)
let end = Date(timeIntervalSince1970: sessionLapTime.lapEndDate)
healthStoreService.fetchWorkoutData(startDate: start, endDate: end) { (success, error) in
complete(storedSessionLapTime, nil)
}
}
}
MyfetchSessionLapTimes
函数定义如下:
func fetchWorkoutData(startDate: Date, endDate: Date, completion: ((_ success: Bool, _ error: Error?) -> Void)!) {
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
let query = HKSampleQuery(sampleType: hrType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: nil) {
query, results, error in
guard let samples = results as? [HKQuantitySample] else {
completion(false, error)
fatalError("Error fetching workout data: \(error!.localizedDescription)");
}
if samples.count < 1 {
self.debug.log(tag: "HealthStoreService", content: "No workout data found")
completion(true, nil)
return
}
DispatchQueue.main.async {
for sample in samples {
self.debug.log(tag: "HealthStoreService", content: "\(sample.quantity.doubleValue(for: self.hrUnit))")
}
completion(true, nil)
return
}
}
healthStore.execute(query)
}
func fetchWorkoutData(开始日期:日期,结束日期:日期,完成日期:((uu成功:Bool,u错误:error?->Void)!){
let predicate=HKQuery.predicateForSamples(具有开始:startDate,结束:endDate,选项:.strictStartDate)
let query=HKSampleQuery(sampleType:hrType,谓词:谓词,限制:Int(hkObjectQueryOnlimit),sortDescriptors:nil){
查询、结果、中的错误
guard let samples=结果为?[HKQuantitySample]其他{
完成(错误,错误)
fatalError(“获取训练数据时出错:\(错误!.localizedDescription)”;
}
如果样本数小于1{
self.debug.log(标记:“HealthStoreService”,内容:“未找到任何训练数据”)
完成(真,无)
返回
}
DispatchQueue.main.async{
样品中的样品{
self.debug.log(标记:“HealthStoreService”,内容:“\(sample.quantity.doubleValue(for:self.hrUnit)))
}
完成(真,无)
返回
}
}
healthStore.execute(查询)
}
正如您所看到的,这个函数也是异步的。如果我运行这个代码,我不会返回所有圈的心率数据在允许返回
FetchSessionAdaptimes
之前,如何确保我拥有所有圈数的心率数据?您可以将for
循环中的所有fetchWorkoutData
任务添加到调度组中。当它们全部完成时,您将收到通知,因此您可以调用函数的完成。以下是一个例子:
func fetchSessionLapTimes(session: Session, withCompletion complete: ((_ storedSessionLapTime: [SessionLapTime], _ error: Error?) -> Void)!) {
var storedSessionLapTime = [SessionLapTime]()
managedObjectContext.performAndWait {
//
}
// Here you were putting async calls to a for loop and couldn't tell when all were completed
// DispatchGroup is made exactly to handle this
let dispatchGroup = DispatchGroup()
let healthStoreService = HealthStoreService()
for sessionLapTime in storedSessionLapTime {
let start = Date(timeIntervalSince1970: sessionLapTime.lapStartDate)
let end = Date(timeIntervalSince1970: sessionLapTime.lapEndDate)
// Adding the task to group
dispatchGroup.enter()
healthStoreService.fetchWorkoutData(startDate: start, endDate: end) { (success, error) in
// notifying when this particular task finishes
dispatchGroup.leave()
}
}
// completion is called only when all of the DispatchGroup tasks are finished
dispatchGroup.notify(queue: .main) {
// call completion here because all tasks completed
complete(storedSessionLapTime, nil)
}
}
您可以使用信号灯
或从属操作队列
。您还可以使用promise kit,如或在第一次完成fetchWorkoutData
时调用completion block。尝试使用依赖项操作您可以将当前在for
循环中调用的任务添加到DispatchGroup
中,并在所有任务完成时收到通知。然后启动fetchSessionLapTimes
的完成。检查这个