Swift中如何将HKSampleQuery闭包内的值传递到全局变量?
解决HKSampleQuery闭包内值无法在外部正常获取的问题
你的问题核心是HKSampleQuery的闭包是异步执行的——外部打印全局变量的代码会比闭包内的赋值代码先运行,所以你在外部打印时,变量还没被更新,自然看不到赋值后的结果;而闭包内打印正常,是因为那时候赋值操作已经完成了。
下面给你两种实用的解决方案:
方案1:自定义回调闭包
通过定义回调闭包传递获取到的Date值,所有需要用到这个值的逻辑都放在回调内执行:
import HealthKit let healthStore = HKHealthStore() // 定义回调类型,用于传递查询到的日期 typealias DateCompletion = (Date?) -> Void func fetchLatestSampleDate(completion: @escaping DateCompletion) { // 确认要查询的健康数据类型(这里以心率为例,可替换为你需要的类型) guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate) else { completion(nil) return } // 构建查询条件:查询从过去到当前的样本,按时间倒序取最近1条 let predicate = HKQuery.predicateForSamples(withStart: Date.distantPast, end: Date(), options: .strictEndDate) let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false) let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: 1, sortDescriptors: [sortDescriptor]) { _, samples, error in // 处理查询结果 guard let sample = samples?.first as? HKQuantitySample, error == nil else { completion(nil) return } // 获取样本日期并通过回调返回 completion(sample.startDate) } healthStore.execute(query) } // 调用方法,在回调内处理日期 fetchLatestSampleDate { date in if let targetDate = date { print("获取到的日期:\(targetDate)") // 所有需要使用该日期的逻辑都写在这里,比如更新UI、数据计算等 } else { print("日期获取失败") } }
方案2:使用Async/Await(iOS 15+ / macOS 12+)
如果你的项目支持iOS15及以上版本,用Swift的async/await语法会更简洁,代码可读性更高:
import HealthKit let healthStore = HKHealthStore() func fetchLatestSampleDate() async throws -> Date? { guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate) else { return nil } let predicate = HKQuery.predicateForSamples(withStart: Date.distantPast, end: Date(), options: .strictEndDate) let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false) // 使用HKHealthStore的异步execute方法 let samples = try await healthStore.execute(HKSampleQuery( sampleType: sampleType, predicate: predicate, limit: 1, sortDescriptors: [sortDescriptor] )) guard let sample = samples.first as? HKQuantitySample else { return nil } return sample.startDate } // 在异步上下文内调用方法(比如Task、async函数中) Task { do { if let targetDate = try await fetchLatestSampleDate() { print("获取到的日期:\(targetDate)") // 在这里处理日期相关逻辑 } else { print("日期获取失败") } } catch { print("查询出错:\(error.localizedDescription)") } }
注意事项
不要用sleep()之类的同步阻塞方式等待异步结果,这不仅无法等到正确值,还会阻塞主线程导致APP卡顿。必须通过异步方式(回调或async/await)处理HKSampleQuery的查询结果。
内容的提问来源于stack exchange,提问作者codelearner
相关产品推荐
相关产品推荐

