原文:HealthKit Tutorial with Swift: Getting Started
作者:Ted Bendixson
译者:kmyhy更新说明:本教程由 Ted Bendixson 升级至 Swift 4、Xcode 9 及 iOS 11。原教程作者是Ernesto García。
HealthKit 从 iOS 8 开始出现。它实际上是一个关于所有健康数据的集中式存储库,允许用户构建一个生物数据库并存储健康数据。
在这篇 HealthKit 教程中,你将创建一个简单的跟踪健康数据的 App,同时学习:
准备开始 HealthKit 的练习了吗?请继续阅读!
注意:要完成本 HealthKit 教程,你需要有一个有效的 iOS 开发者账号。否则,你无法开启 HealthKit 能力并访问 HealthKit 数据库。
开始
这个示例 App 会记录了最新的明星健身课程的卡路里消耗。对于好莱坞圈内人士和社会名流来说,应该对 Prancercise 不陌生(一种时髦的健身方式)。
先下载开始项目,用 Xcode 打开。
Build & run。你可以看一下 UI 框架。在后续的两个系列课程中,你会逐渐添加功能。
指定 Team
HealthKit 框架有点特殊。如果你没有一个激活的开发者账号你无法使用它。如果你有开发者账号,你就可以指定你的 Team 了。
在项目导航器中选中 PrancerciseTracker,然后选择 PrancerciseTracker 这个 target。选择 General,点击 Team 下拉框。
选择和你的开发者账号所对应的 Team:
很简单,是吧?我想说,要想卡路里低,土豆红豆炖蔬菜汤。
授权
HealthKit 需要授权,为了在 app 使用该框架,你还必须开启它们。
在 target 编辑器中打开 Capabilities,打开 HealthKit 开关,如下图所示:
然后等待 Xcode 配置 HealthKit。正常情况下会很顺利,但如果你忘记在上一节中配置你的 Team 和 Buindle ID,就可能会遇上麻烦。
完成这一步后,你就需要向用户询问 HealthKit 权限了。
请求许可
HealthKit 会用到敏感和隐私数据。没有人会允许 app 随意访问这些信息。
那也是为什么 HealthKit 需要一个强壮的隐私系统。HealthKit 只能访问用户同意分享给它的数据。要为 Prancercise Tracker 用户构建一个健康档案,你必须做一个君子并事先请求需要访问到的每种数据。
修改共享描述
首先,你必须阐述你为什么需要向用户请求健康指标。Xcode 允许你通过 Info.plist 文件对此进行设置。
打开 Info.plist,添加 2 个 key:
Privacy – Health Share Usage Description
Privacy – Health Update Usage Description
这两个 key 是文本类型,用于在 HealthKit 请求授权窗口显示时显示一些文字。Health Share Usage Description 用于从 HealthKit 读取数据。Health Update Usage Description 用于向 HealthKit 写入数据。
这里的内容你可以随意填写。它只是一些描述性说明,比如“我们将使用你的健康信息用于更好地记录 Prancercise 练习。”
注意,如果不设置这两个 key,app 会在试图授权 HealthKit 时崩溃。
授权 HealthKit
打开 HealthKitSetupAssistant.swift 看一眼。你会看到一个空类,一个 Error 类型,以及一个方法,我们用这个方法来对 HealthKit 获取授权。
class func authorizeHealthKit(completion: @escaping (Bool,Error?) -> Swift.Void) { }
authorizeHealthKit(completion:) 方法不需要参数,它只有一个完成块用于返回一个布尔值(表示成功或失败)以及一个可空的 error 用于发生异常时进行处理。错误可能有两种常。你可以在两种特殊情况下将错误传递给完成块。
参考答案:当请求授权时可能发生什么错误?
- HealthKit 在该设备上无效。这会在 iPad 上出现。
- 某些数据类型可能在当前版本的 HealthKit 上无效。
让我们来分成几个步骤。要请求 HealthKit 授权,authorizeHealthKit(completion:) 方法必须做几件事情:
- 检查 HealthKit 是否在设备上有效。如果无效,返回失败和错误。
- 准备 Prancercise Tracker 将要读取和写到 HealthKit 中的健康数据的类型。
- 将这些数据放到一个读取/写入类型的数组中。
- 请求授权。如果成功,返回成功并结束。
检查 HealthKit 是否有效
首先第一件事情。你将检查 HealthKit 是否在该设备上有效。
将下列代码粘贴到 authorizeHealthKit(completion:) 方法头部:
//1. 检查 HealthKit 是否在设备上有效
guard HKHealthStore.isHealthDataAvailable() else {
completion(false,HealthkitSetupError.notAvailableOnDevice)
return
}
你会和 HKHealthStore 经常打交道。它表示用于存放用户健康数据的中心数据库。它的 isHealthDataAvailable() 方法帮你判断用户当前设备是否支持 HealthKit 数据。
guard 语句在 HealthKit 在该设备上无效是终止这个方法的其它代码执行。如果这种情况发生,会返回 notAvailableOnDevice 错误。你的 View Controller 收到后会进行适当处理,或者仅仅在控制台中输出。
准备数据类型
一旦明确 HealthKit 在用户设备上有效,就应该准备从 HealthKit 进行读写的数据类型了。
HealthKit 使用了一种类型叫做 HKObjectType。每个出入 HealthKit 中央存储库的类型都应当是一种 HKObjectdType 类型。你还会看到 HKSampleType 和 HKWorkoutType。这两个都继承了 HKObjectType,因此它们本质上是一样的。
//2. Prepare the data types that will interact with HealthKit
guard let dateOfBirth = HKObjectType.characteristicType(forIdentifier: .dateOfBirth),let bloodType = HKObjectType.characteristicType(forIdentifier: .bloodType),let biologicalSex = HKObjectType.characteristicType(forIdentifier: .biologicalSex),let bodyMassIndex = HKObjectType.quantityType(forIdentifier: .bodyMassIndex),let height = HKObjectType.quantityType(forIdentifier: .height),let bodyMass = HKObjectType.quantityType(forIdentifier: .bodyMass),let activeEnergy = HKObjectType.quantityType(forIdentifier: .activeEnergyBurned) else {
completion(false,HealthkitSetupError.dataTypeNotAvailable)
return
}
哇,好长的 guard 语句!这是一个通过单个 guard 语句解包多个可空值的绝佳例子。
为了创建一个针对指定生物学特性或数值的 HKObjectType,你必须使用 HKObjectType.characteristicType(forIdentifier:) 或者 HKObjectType.quantityType(forIdentifier:) 方法。
无论特征类型还是数值类型,都被框架定义为枚举。HealthKit HealthKit 会加载这些。你的 app 需要记录关于健康的方方面面,这使我在做 Prancercise 的同时头晕脑涨。
你也会看到,如果某个特性或抽样类型无效,这个方法会返回错误。这是我们故意的。你的 app 理应知道它要用到的一切 HealthKit 类型。
准备要读或写的数据类型列表
现在来准备要读或者写的数据的类型数组。
将第三段代码粘贴到 authorizeHealthKit(completion:) 方法的第二段代码之后:
//3. Prepare a list of types you want HealthKit to read and write
let healthKitTypesToWrite: Set<HKSampleType> = [bodyMassIndex,activeEnergy,HKObjectType.workoutType()]
let healthKitTypesToRead: Set<HKObjectType> = [dateOfBirth,bloodType,biologicalSex,bodyMassIndex,height,bodyMass,HKObjectType.workoutType()]
HealthKit 需要一个你用户可以写入的数据类型的 HKSampleType 对象集合,以及一个 app 能够读取的数据类型的 HKObjectType 对象集合。
HKObjectType.workoutType() 是一种特设的 HKObjectType 类型。它用于代表任意类型的练习。
授权 HealthKit
最后一步非常简单。你只需要请求 HealthKit 授权。在第三段代码之后粘贴最后一段代码:
//4. Request Authorization
HKHealthStore().requestAuthorization(toShare: healthKitTypesToWrite,read: healthKitTypesToRead) { (success,error) in
completion(success,error)
}
这句代码请求 HealthKit 授权,然后调用 completion 回调块。它使用了 HKHealthStore 的 requestAuthorization(toShare: read: completion:) 方法传入的 success 和 error 对象。
你可以认为这是某种重定向。取代在 HealthKitSetupAssistant 中处理 completion,你现在将任务交给 View Controller 来做,这样它就可以弹出一个 alert 或者执行其它动作。
开始项目中已经有一颗 HealthKit 按钮,它会调用 MasterViewController 的 authorizeHealthKit() 方法。这貌似就是调用你刚刚写完的新授权方法的地方。
打开 MasterViewController.swift,找到 authorizeHealthKit() 将下列代码粘贴到方法中:
HealthKitSetupAssistant.authorizeHealthKit { (authorized,error) in
guard authorized else {
let baseMessage = "HealthKit Authorization Failed"
if let error = error {
print("\(baseMessage). Reason: \(error.localizedDescription)")
} else {
print(baseMessage)
}
return
}
print("HealthKit Successfully Authorized.")
}
这段代码调用了刚刚写的那个 authorizeHealthKit(completion:) 方法。当它完成时,它会打印控制台消息告诉你 HealthKit 是否成功授权。
Build & run。点击 main view 中的 Authorize HealthKit 按钮,你会看到授权界面弹出:
打开所有开关选项,拉动屏幕查看所有选项,然后点击 Allow。你会在 Xcode 控制台中看到:
HealthKit Successfully Authorized.
很好!你的 app 已经能够访问 HealthKit 的集中存储仓库了。时候开始记录一点东西了。
特性和抽样
在这一节,你将学习:
- 如何读取用户的生物学特性
- 如何读和写各种抽样类型(身高、体重等)
生物学特征是不能改变的东西,比如血型。而抽样表示经常会改变的东西,比如体重。
为了正确记录一次 Prancercise 练习的效果,Prancercise Tracker app 必须获得用户的体重和身高。两者放在一起,这个抽样会被计算成 BMI(Body Mass Index 体质指数)。
注意:BMI 普遍用于表示身体的脂肪,它是通过一个人的身高和体重来计算的。请参考这里。
读取特性
Prancercise Tracker app 不会对生物学特性进行写操作。它只会读取它们。这意味着必须首先将这写特性保存到 HealthKit 的集中式存储仓库中。
如果你没有保存过这些数据,请现在来告诉 HealthKit。
打开手机或模拟器上的 Health app。选择 Health Data(健康数据) tab。点击右上角的 profile 图标,查看你的健康档案。点击编辑,输入生日、性别、血型:
现在,HealthKit 已经知道你的生日、性别和血型了,我们来将这些特性读到 Prancercise Tracker 中。
回到 Xcode,打开 ProfileDataStore.swift。这个类是你访问用户所有健康数据的入口点。
将这个方法粘贴到 ProfileDataStore:
class func getAgeSexAndBloodType() throws -> (age: Int,biologicalSex: HKBiologicalSex,bloodType: HKBloodType) {
let healthKitStore = HKHealthStore()
do {
//1. This method throws an error if these data are not available.
let birthdayComponents = try healthKitStore.dateOfBirthComponents()
let biologicalSex = try healthKitStore.biologicalSex()
let bloodType = try healthKitStore.bloodType()
//2. Use Calendar to calculate age.
let today = Date()
let calendar = Calendar.current
let todayDateComponents = calendar.dateComponents([.year],from: today)
let thisYear = todayDateComponents.year!
let age = thisYear - birthdayComponents.year!
//3. Unwrap the wrappers to get the underlying enum values.
let unwrappedBiologicalSex = biologicalSex.biologicalSex
let unwrappedBloodType = bloodType.bloodType
return (age,unwrappedBiologicalSex,unwrappedBloodType)
}
}
getAgeSexAndBloodType() 方法会访问 HKHealthStore,获取用户的生日、性别和血型。还会通过生日计算出用户的年龄。
- 你可能会注意到这个方法会抛出异常。当 HealthKit 的中央存储库中没有保存用户的生日、性别或血型时,会抛出这个错误。因为你已经在健康 app 中输入过这些信息,因此不应该有错误发生。
- 用 Calendar 类,将 NSDate 转换成一系列日期组件。如果你想获取年份,这是一种很好的方法。这段代码直接获得出生年份和本年度年份,然后进行比较。
- 解包,将结果赋给两个变量,这需要访问到包装类(HKBiologicalSexObject 和 HKBloodTypeObjecd)底层的枚举。
修改 UI
如果你现在 build& run,你会发现 UI 没有任何改变,因为还没有将逻辑和 UI 关联起来。
打开 ProfileViewController.swift,找到 loadAndDisplayAgeSexAndBoodType() 方法。
这个方法会调用你的 ProfileDataSource 方法将生物学特性加载到 UI 上。
do {
let userAgeSexAndBloodType = try ProfileDataStore.getAgeSexAndBloodType()
userHealthProfile.age = userAgeSexAndBloodType.age
userHealthProfile.biologicalSex = userAgeSexAndBloodType.biologicalSex
userHealthProfile.bloodType = userAgeSexAndBloodType.bloodType
updateLabels()
} catch let error {
self.displayAlert(for: error)
}
这段代码加载了年龄、性别和血型元组。然后将这些字段赋给局部变量 UerHealthProfile 模型。最后,调用 updateLabels() 刷新 UI。
因为 ProfileDataStore 的 getAgeSexAndBloodType() 方法会抛出异常,你的 ProfileViewController 必须处理这个异常。在这里,你直接将错误用一个带 OK 按钮的 alert 来展示。
这很好,但有一个问题。updateLabels() 还没有内容,它只是一个空的声明。这次让我们用它来和 UI 进行联动。
找到 updateLabels() 方法,将下列代码粘贴到方法中:
if let age = userHealthProfile.age {
ageLabel.text = "\(age)"
}
if let biologicalSex = userHealthProfile.biologicalSex {
biologicalSexLabel.text = biologicalSex.stringRepresentation
}
if let bloodType = userHealthProfile.bloodType {
bloodTypeLabel.text = bloodType.stringRepresentation
}
代码十分简单。如果用户的年龄存在,将格式化的你年龄显示到 label 上。血型和性别也是一样处理。stringRepresentation 变量将枚举转换为字符串显示。
Build & run。进入 Profile & BMI 界面,点击 Read HealthKit Data 按钮。
如果你之前在健康 app 中输入了信息,它会在屏幕上显示这些 label。否则,你会得到错误提示。
很好!你成功从 HealthKit 读取并显示了数据。
查询样本
现在是时候读取用户的身高和体重了。它们将用于计算 BMI 并显示在 profile 视图。
生物学特性很容易拿到,因为它们几乎从不会改变。样本则需要更复杂一些。它们需要使用 HKQuery,尤其是 HKSampleQuery。
要从 HealthKit 查询样本,你必须:
- 指定要查询的样本类型(体重、身高等)。
- 用于过滤和排序的参数。你可以掺入一个可空的 NSPredicate 或者 NSSortDescriptors。
注意:如果你熟悉 Core Data,你可能觉得这很熟悉。一个 HKSampleQuery 和某个实体类型的 NSFetchedRequest 很像,你也可以指定 predicate 和 sort descriptor,然后请求对象上下文执行查询,返回结果。
当查询创建好,你直接调用 HKHealthStore 的 executeQuery() 方法还抓取结果。
在 Prancercise Tracker 中,你将创建一个加载所有类型最新样本数据的共用方法。这样,你可以在身高和体重上都使用它。
打开 ProfileDataStore.swift,将下列方法粘贴到类的 getAgeSexAndBlooodType() 后面:
class func getMostRecentSample(for sampleType: HKSampleType,completion: @escaping (HKQuantitySample?,Error?) -> Swift.Void) {
//1. Use HKQuery to load the most recent samples.
let mostRecentPredicate = HKQuery.predicateForSamples(withStart: Date.distantPast,end: Date(),options: .strictEndDate)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate,ascending: false)
let limit = 1
let sampleQuery = HKSampleQuery(sampleType: sampleType,predicate: mostRecentPredicate,limit: limit,sortDescriptors: [sortDescriptor]) { (query,samples,error) in
//2. Always dispatch to the main thread when complete.
DispatchQueue.main.async {
guard let samples = samples,let mostRecentSample = samples.first as? HKQuantitySample else {
completion(nil,error)
return
}
completion(mostRecentSample,nil)
}
}
HKHealthStore().execute(sampleQuery)
}
这个方法带一个样本类型参数(身高、体重、bmi 等)。然后针对指定类型来构建抓取最近样本的查询。如果你指定的样本类型是体重,它会返回你最新的体重数据。
这个过程比较复杂,我将分成几个步骤进行讲解。
- HKQuery 有许多方法允许你过滤你的 HealthKit 样本查询。了解一下它们是值得的。在这里,我们使用了内置的日期窗口 predicate。
- 向 HealthKit 查询样本是一个异步的过程。所以要将完成块方到一个 Dispatch 块中进行调用。你需要让完成块在主线程中执行,这样 UI 才能响应。如果不这样做,app 则会崩溃。
如果一切顺利,你的查询会执行,你会在主线程中获得漂亮的样本数据,你的 ProfileViewController 会将数据展示到 label 中。我们继续完成这部分内容。
在 UI 中显示样本数据
还记得上一节中的内容吗?你从 HealthKit 中加载数据,将数据保存到 ProfileViewController 的模型对象,然后用 ProfileViewController 的 updateLabels() 方法刷新 label 中的显示内容。
现在你需要做的就是添加一个函数加载样本数据,根据 UI 对它们进行处理,然后调用 updateLabels() 将文本显示到 label。
打开 ProfileViewController.swift,找到 loadAndDisplayMostRecentHeight() 方法,将下列代码粘贴进去:
//1. Use HealthKit to create the Height Sample Type
guard let heightSampleType = HKSampleType.quantityType(forIdentifier: .height) else {
print("Height Sample Type is no longer available in HealthKit")
return
}
ProfileDataStore.getMostRecentSample(for: heightSampleType) { (sample,error) in
guard let sample = sample else {
if let error = error {
self.displayAlert(for: error)
}
return
}
//2. Convert the height sample to meters,save to the profile model,
// and update the user interface.
let heightInMeters = sample.quantity.doubleValue(for: HKUnit.meter())
self.userHealthProfile.heightInMeters = heightInMeters
self.updateLabels()
}
- 这个方法一开始创建了一个 Height 样本类型。然后将这个样本类型传入到刚才写的那个方法,这会返回 HealthKit 中保存的最新的身高样本。
- 当样本数据返回,将身高转换成米,然后保存到 UserHealthProfile 模型。然后刷新 label。
注意:一般情况下你会想将数字的样本转换成某种标准单位。上述代码利用了 HKQuantitySample 的 doubleValue(for:) 方法,这个方法允许你传入一个 HKUnit 指定你想要的单位(比如米)。
你可以用 HKUnit 中的一些通用的类方法来构造各种在 HealthKit 中有效的类型。要获得米,只需要调用 HKUnit() 的 meter() 方法就可以了。
那只是身高。体重呢?也是同样的方法,但是在 ProfileViewController 的 loadAndDisplayMostRecenWeight() 方法中进行了。
将下列代码粘贴进 loadAndDisplayMostRecentWeight() 方法中:
guard let weightSampleType = HKSampleType.quantityType(forIdentifier: .bodyMass) else {
print("Body Mass Sample Type is no longer available in HealthKit")
return
}
ProfileDataStore.getMostRecentSample(for: weightSampleType) { (sample,error) in
guard let sample = sample else {
if let error = error {
self.displayAlert(for: error)
}
return
}
let weightInKilograms = sample.quantity.doubleValue(for: HKUnit.gramUnit(with: .kilo))
self.userHealthProfile.weightInKilograms = weightInKilograms
self.updateLabels()
}
基本上是一个模式。你创建了想要的样本类型,请求 HealthKit,进行一点单位转换,保存到模型,刷新 UI。
这时,你可能觉得结束了,但还有一件事情要做。updateLabels() 函数还对新数据一无所知,你必须让它知道。我们来修改它。
在 updateLabels() 函数的解包 bloodType 并显示到 label 的代码后面添加:
if let weight = userHealthProfile.weightInKilograms {
let weightFormatter = MassFormatter()
weightFormatter.isForPersonMassUse = true
weightLabel.text = weightFormatter.string(fromKilograms: weight)
}
if let height = userHealthProfile.heightInMeters {
let heightFormatter = LengthFormatter()
heightFormatter.isForPersonHeightUse = true
heightLabel.text = heightFormatter.string(fromMeters: height)
}
if let bodyMassIndex = userHealthProfile.bodyMassIndex {
bodyMassIndexLabel.text = String(format: "%.02f",bodyMassIndex)
}
完全遵循 updateLabels() 函数原有的模式,它对 UserHeathProfile 模型中的身高、体重和 bmi 进行了拆包操作。如果这些值有效,它会生成正确的字符串显示到 label 中。MassFormatter 和 LengthFormatter 负责将数字转换成字符串。
BMI 实际上没有保存到 UserHealthProfile 模型。它只是一个计算属性为你算出了这个值。
用 cmd+鼠标左键,点击 bodyMassIndex 属性,你就知道我所说的了:
var bodyMassIndex: Double? {
guard let weightInKilograms = weightInKilograms,let heightInMeters = heightInMeters,heightInMeters > 0 else {
return nil
}
return (weightInKilograms/(heightInMeters*heightInMeters))
}
bodyMassIndex 是一个可空属性,如果 height 或 weight 没有设置(或者它们被设置为某些不正常的数字),它会返回 nil。其实它只是用体重除以身高的平方算出的。
注意:如果你没有在 HealthKit Store 中存入 app 需要的数据,那么你很快就会有麻烦了。如果你还没有这样做,你起码需要输入一些身高和体重数据。
打开健康 app,导航到健康数据 tab。然后选择身体测量选项,选中体重,然后添加数据点,添加一个新的体重样本。重复同样步骤以添加身高。
这时,Prancercise Tracker 就能够读到用户最新的体重和身高了,然后就会显示在 label 中。
Build & run。打开 Profile & BMI。然后点击 Read HealthKit Data 按钮。
很好!你第一次从 HealthKit Store 读取了抽样并用于计算 BMI。
保存样本
Prancercise Tracker 已经拥有一个好用的 BMI 计算器。让我们来用它记录用户的 BMI 抽样数据。
打开 ProfileDataStore.swift 添加方法:
class func saveBodyMassIndexSample(bodyMassIndex: Double,date: Date) {
//1. Make sure the body mass type exists
guard let bodyMassIndexType = HKQuantityType.quantityType(forIdentifier: .bodyMassIndex) else {
fatalError("Body Mass Index Type is no longer available in HealthKit")
}
//2. Use the Count HKUnit to create a body mass quantity
let bodyMassQuantity = HKQuantity(unit: HKUnit.count(),doubleValue: bodyMassIndex)
let bodyMassIndexSample = HKQuantitySample(type: bodyMassIndexType,quantity: bodyMassQuantity,sta健康rt: date,end: date)
//3. Save the same to HealthKit
HKHealthStore().save(bodyMassIndexSample) { (success,error) in
if let error = error {
print("Error Saving BMI Sample: \(error.localizedDescription)")
} else {
print("Successfully saved BMI Sample")
}
}
}
看起来有点眼熟。和其它样本类型一样,你首先需要确保样本类型在 HealthKit 中是可用的。
- 这里,代码检查了是否有一种量的类型叫做 body mass index。如果有,用它来创建一个量和一个量的样本。如果没有,故意让 app 崩溃。
- HKUnit 的 count 方法有点特殊,如果要存储的样本的类型没有具体的单位时你可以用这个方法。在未来的某些时候,可能会为 bmi 指定专门的单位,但就目前来说,指定一个泛泛的单位就可以了。
- 用 HKHealthStore 保存样本并通过尾随闭包通知你是否成功。通过这个闭包你可以进行进一步的处理,但就目前来说只需要输出一下控制台就可以了。
接近完成了。让我们把它和 UI 关联起来。
打开 ProfileViewController.swift,找到 saveBodyMassIndexToHealthKit() 方法。这个方法在用户点击 table view 中的 Save BMI 按钮时调用。
guard let bodyMassIndex = userHealthProfile.bodyMassIndex else {
displayAlert(for: ProfileDataError.missingBodyMassIndex)
return
}
ProfileDataStore.saveBodyMassIndexSample(bodyMassIndex: bodyMassIndex,date: Date())
还记得 bmi 是一个计算属性,它是由 HealthKit 中的身高体重计算而来的吗?这段代码尝试计算出这个属性,如果成功的话,将它传递给刚刚写的 savedBodyMassIndexSample(bodyMassIndex:date:) 方法。
如果因为某种原因无法算出 bmi,它会显示警告信息。
Build & run。进入 Profile & BMI 界面。从 HealthKit 加载你的信息,然后点击 Save BMI 按钮。
看一眼控制台,你看到了什么?
Successfully saved BMI Sample
如果你看见这个,那么恭喜了!你的 BMI 样本成功保存到了 HealthKit 的中央存储库中。我们来试着看看能不能找出它。
打开健康 app,点击健康数据 tab,点击 table view 中的身体测量,然后点击体质指数。
除非你经常保存你的体质指数(就像所有成绩好的 Prancerciser 达人一样),否则你只会看到一个数据点:
太好了。你可以在苹果的健康 app 中看见你自己的 app 创建的样本了。这给予了无限可能。
接下来做什么?
恭喜你!你已经对 HealthKit 有了切身体会!你知道如何请求权限,读取生物学特性,读取和写入样本。
如果你想继续学习,请关注下一部分系列教程,在那里你将学到更多的一种复杂数据类型:workouts。
另外,如果你有任何问题和意见,请在下面的留言!
原文链接:https://www.f2er.com/swift/320999.html