如何使用 Swift 从 iOS HealthKit 应用程序读取心率?
Posted
技术标签:
【中文标题】如何使用 Swift 从 iOS HealthKit 应用程序读取心率?【英文标题】:How to read heart rate from iOS HealthKit app using Swift? 【发布时间】:2015-09-10 04:50:04 【问题描述】:我正在使用以下 Swift 代码。
let sampleType : HKSampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)
let nowDate: NSDate = NSDate()
var calendar: NSCalendar = NSCalendar.autoupdatingCurrentCalendar()
let yearMonthDay: NSCalendarUnit = NSCalendarUnit.YearCalendarUnit | NSCalendarUnit.MonthCalendarUnit | NSCalendarUnit.DayCalendarUnit
var components: NSDateComponents = calendar.components(yearMonthDay , fromDate: nowDate)
var beginOfDay : NSDate = calendar.dateFromComponents(components)!
var predicate : NSPredicate = HKQuery.predicateForSamplesWithStartDate(beginOfDay, endDate: nowDate, options: HKQueryOptions.StrictStartDate)
let squery: HKStatisticsQuery = HKStatisticsQuery(quantityType: sampleType, quantitySamplePredicate: predicate, options: HKStatisticsOptions.None) (qurt, resul, errval) -> Void in
dispatch_async( dispatch_get_main_queue(), () -> Void in
var quantity : HKQuantity = result.averageQuantity;
var beats : double = quantity.doubleValueForUnit(HKUnit.heartBeatsPerMinuteUnit())
// [quantity doubleValueForUnit:[HKUnit heartBeatsPerMinuteUnit]];
self.txtfldHeartRate.text = "\(beats)"
)
healthManager.healthKitStore.executeQuery(squery)
我收到以下错误消息:
找不到接受类型为“(quantityType: HKSampleType, quantitySamplePredicate: NSPredicate, options: HKStatisticsOptions, (_, _, _) -> Void)”的参数列表的“HKStatisticsQuery”类型的初始化器
请告诉我如何解决这个问题。
【问题讨论】:
【参考方案1】:从 ViewController 读取数据(不是 Apple Watch 扩展)
斯威夫特 5
let health: HKHealthStore = HKHealthStore()
let heartRateUnit:HKUnit = HKUnit(from: "count/min")
let heartRateType:HKQuantityType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!
var heartRateQuery:HKSampleQuery?
/*Method to get todays heart rate - this only reads data from health kit. */
func getTodaysHeartRates()
//predicate
let calendar = NSCalendar.current
let now = NSDate()
let components = calendar.dateComponents([.year, .month, .day], from: now as Date)
guard let startDate:NSDate = calendar.date(from: components) as NSDate? else return
var dayComponent = DateComponents()
dayComponent.day = 1
let endDate:NSDate? = calendar.date(byAdding: dayComponent, to: startDate as Date) as NSDate?
let predicate = HKQuery.predicateForSamples(withStart: startDate as Date, end: endDate as Date?, options: [])
//descriptor
let sortDescriptors = [
NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
]
heartRateQuery = HKSampleQuery(sampleType: heartRateType, predicate: predicate, limit: 25, sortDescriptors: sortDescriptors, resultsHandler: (query, results, error) in
guard error == nil else print("error"); return
self.printHeartRateInfo(results: results)
) //eo-query
health.execute(heartRateQuery!)
//eom
/*used only for testing, prints heart rate info */
private func printHeartRateInfo(results:[HKSample]?)
for (_, sample) in results!.enumerated()
guard let currData:HKQuantitySample = sample as? HKQuantitySample else return
print("[\(sample)]")
print("Heart Rate: \(currData.quantity.doubleValue(for: heartRateUnit))")
print("quantityType: \(currData.quantityType)")
print("Start Date: \(currData.startDate)")
print("End Date: \(currData.endDate)")
print("Metadata: \(currData.metadata)")
print("UUID: \(currData.uuid)")
print("Source: \(currData.sourceRevision)")
print("Device: \(currData.device)")
print("---------------------------------\n")
//eofl
//eom
斯威夫特 3
let health: HKHealthStore = HKHealthStore()
let heartRateUnit:HKUnit = HKUnit(fromString: "count/min")
let heartRateType:HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!
var heartRateQuery:HKSampleQuery?
/*Method to get todays heart rate - this only reads data from health kit. */
func getTodaysHeartRates()
//predicate
let calendar = NSCalendar.currentCalendar()
let now = NSDate()
let components = calendar.components([.Year,.Month,.Day], fromDate: now)
guard let startDate:NSDate = calendar.dateFromComponents(components) else return
let endDate:NSDate? = calendar.dateByAddingUnit(.Day, value: 1, toDate: startDate, options: [])
let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: .None)
//descriptor
let sortDescriptors = [
NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
]
heartRateQuery = HKSampleQuery(sampleType: heartRateType,
predicate: predicate,
limit: 25,
sortDescriptors: sortDescriptors)
(query:HKSampleQuery, results:[HKSample]?, error:NSError?) -> Void in
guard error == nil else print("error"); return
//self.printHeartRateInfo(results)
self.updateHistoryTableViewContent(results)
//eo-query
health.executeQuery(heartRateQuery!)
//eom
/*used only for testing, prints heart rate info */
private func printHeartRateInfo(results:[HKSample]?)
for(var iter = 0 ; iter < results!.count; iter++)
guard let currData:HKQuantitySample = results![iter] as? HKQuantitySample else return
print("[\(iter)]")
print("Heart Rate: \(currData.quantity.doubleValueForUnit(heartRateUnit))")
print("quantityType: \(currData.quantityType)")
print("Start Date: \(currData.startDate)")
print("End Date: \(currData.endDate)")
print("Metadata: \(currData.metadata)")
print("UUID: \(currData.UUID)")
print("Source: \(currData.sourceRevision)")
print("Device: \(currData.device)")
print("---------------------------------\n")
//eofl
//eom
使用 Apple Watch 扩展读取数据:
要在 Apple Watch 中执行查询,请执行以下操作:
heartRateQuery = self.createStreamingQuery()
health.executeQuery(heartRateQuery!)
不要忘记属性:
let health: HKHealthStore = HKHealthStore()
let heartRateUnit:HKUnit = HKUnit(fromString: "count/min")
let heartRateType:HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!
var heartRateQuery:HKQuery?
/*下面的方法没有限制,一旦执行查询就无限查询heart */
private func createStreamingQuery() -> HKQuery
let queryPredicate = HKQuery.predicateForSamplesWithStartDate(NSDate(), endDate: nil, options: .None)
let query:HKAnchoredObjectQuery = HKAnchoredObjectQuery(type: self.heartRateType, predicate: queryPredicate, anchor: nil, limit: Int(HKObjectQueryNoLimit))
(query:HKAnchoredObjectQuery, samples:[HKSample]?, deletedObjects:[HKDeletedObject]?, anchor:HKQueryAnchor?, error:NSError?) -> Void in
if let errorFound:NSError = error
print("query error: \(errorFound.localizedDescription)")
else
//printing heart rate
if let samples = samples as? [HKQuantitySample]
if let quantity = samples.last?.quantity
print("\(quantity.doubleValueForUnit(heartRateUnit))")
//eo-query
query.updateHandler =
(query:HKAnchoredObjectQuery, samples:[HKSample]?, deletedObjects:[HKDeletedObject]?, anchor:HKQueryAnchor?, error:NSError?) -> Void in
if let errorFound:NSError = error
print("query-handler error : \(errorFound.localizedDescription)")
else
//printing heart rate
if let samples = samples as? [HKQuantitySample]
if let quantity = samples.last?.quantity
print("\(quantity.doubleValueForUnit(heartRateUnit))")
//eo-non_error
//eo-query-handler
return query
//eom
如何申请授权?
func requestAuthorization()
//reading
let readingTypes:Set = Set( [heartRateType] )
//writing
let writingTypes:Set = Set( [heartRateType] )
//auth request
health.requestAuthorizationToShareTypes(writingTypes, readTypes: readingTypes) (success, error) -> Void in
if error != nil
print("error \(error?.localizedDescription)")
else if success
//eo-request
//eom
【讨论】:
【参考方案2】:HKStatisticsQuery
不会是我的首选。它用于统计计算(即最小值、最大值、平均值、总和)。
你可以使用简单的HKQuery
:
public func fetchLatestHeartRateSample(
completion: @escaping (_ samples: [HKQuantitySample]?) -> Void)
/// Create sample type for the heart rate
guard let sampleType = HKObjectType
.quantityType(forIdentifier: .heartRate) else
completion(nil)
return
/// Predicate for specifiying start and end dates for the query
let predicate = HKQuery
.predicateForSamples(
withStart: Date.distantPast,
end: Date(),
options: .strictEndDate)
/// Set sorting by date.
let sortDescriptor = NSSortDescriptor(
key: HKSampleSortIdentifierStartDate,
ascending: false)
/// Create the query
let query = HKSampleQuery(
sampleType: sampleType,
predicate: predicate,
limit: Int(HKObjectQueryNoLimit),
sortDescriptors: [sortDescriptor]) (_, results, error) in
guard error == nil else
print("Error: \(error!.localizedDescription)")
return
completion(results as? [HKQuantitySample])
/// Execute the query in the health store
let healthStore = HKHealthStore()
healthStore.execute(query)
【讨论】:
谢谢!它节省了我的时间。【参考方案3】:在初始化期间指定常量和变量的类型在 Swift 中通常是多余的,就像在您的情况下,您指定了父类 HKSampleType
类型而不是其子类 HKQuantityType
。因此,在您的情况下,只需省略类型声明:
let sampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!
let nowDate = NSDate()
var calendar = NSCalendar.autoupdatingCurrentCalendar()
如果您使用 Swift 2.0,您还应该在下一行使用类似数组的语法:
let yearMonthDay: NSCalendarUnit = [NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day]
【讨论】:
【参考方案4】:尝试这种方式,在 Xcode 6.4 中移动完成处理程序似乎为我解决了这个问题-
let squery = HKStatisticsQuery(quantityType: sampleType, quantitySamplePredicate: predicate, options: HKStatisticsOptions.None, completionHandler: (qurt, result, errval) -> Void in
dispatch_async( dispatch_get_main_queue(), () -> Void in
var quantity : HKQuantity = result.averageQuantity();
var beats : Double = quantity.doubleValueForUnit(HKUnit.atmosphereUnit())
// [quantity doubleValueForUnit:[HKUnit heartBeatsPerMinuteUnit]];
)
)
注意:我在闭包中看到了一些编译器错误,因此更改了 2 行以确保编译-
var quantity : HKQuantity = result.averageQuantity();
var beats : Double = quantity.doubleValueForUnit(HKUnit.atmosphereUnit())
【讨论】:
【参考方案5】:您应该在查询中使用HKQuantityType
而不是HKSampleType
:
let squery: HKStatisticsQuery = HKStatisticsQuery(quantityType: HKQuantityTypeIdentifierHeartRate, quantitySamplePredicate: predicate, options: HKStatisticsOptions.None) (qurt, resul, errval) -> Void in
【讨论】:
以上是关于如何使用 Swift 从 iOS HealthKit 应用程序读取心率?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 swift iOS 中使用 swift 高阶函数从本地 json 创建 ViewModel
如何使用 Swift 从 iOS HealthKit 应用程序读取心率?
如何使用 Swift 从 iOS HealthKit 应用程序读取心率?
如何在 IOS 上使用 Swift 解析 JSON,从 PHP 服务脚本发送?