在HealthKit节约训练管理问题解决能力训练,怎么解决

您正在使用IE低版浏览器,为了您的雷锋网账号安全和更好的产品体验,强烈建议使用更快更安全的浏览器
发私信给金红
导语:继去年苹果发布HealthKit移动健康平台之后,苹果今年又推出了ResearchKit医疗研究平台,两者定位究竟有何不同,又有怎样的关系呢?
同步到新浪微博
雷锋网编辑,专注新技术和商业故事报道,创业者或行业交流可加微信号Duras0820
当月热门文章
为了您的账户安全,请
您的邮箱还未验证,完成可获20积分哟!
您的账号已经绑定,现在您可以以方便用邮箱登录
请填写申请人资料HealthKit教程 Swift版:锻炼信息
招聘信息:
(原文:&作者:Ernesto García 译者:&)欢迎回到我们的HealthKit系列教程!在我们系列教程的()中,你已经学到了使用HealthKit开发的基础:读写数据。在这第二篇,同时也是最后一篇中,你将会学到怎么样处理一种更复杂的数据类型:锻炼与健身的信息(Workout)。这篇教程从上一篇教程结束的地方开始,所以如果你还没有上一篇中完成的工程,你可以从。开始单从身体方面来说,一个人的锻炼与健身信息由一段时间内做过的身体素质锻炼组成。而再加上数字化的方面来看,你可以通过下面的这些基本属性来得到一条锻炼信息:运动的种类。例如:跑步、骑行、冰壶等距离起止时间持续时间运动时消耗的能量。数字化的领域就是指的HealthKit了,一条锻炼信息就是一个其他类型的数据采样信息(samples)的容器。例如,你可以添加一组数据,来表示在你运动时的心率。如果你打算做一款健康类型的app,那么这将是一个功能强大的特性。在该工程中,你将会存储跑步锻炼时的信息,当然你也可以很容易地改变活动的种类来表示其他类型的锻炼信息。我们的起始项目中已经包含了一个视图控制器,来为你提供查看健康信息的入口。导航到Workouts栏然后点击+按钮你就能看到了。当你停止运动时,会在该页面收集信息并且展示到Workouts视图控制器中。你需要使用这些信息来创建一条健康信息。保存锻炼信息首先,你将创建一个方法来保存跑步时的信息。打开HealthManager.swift,添加如下方法:func&saveRunningWorkout(startDate:NSDate&,&endDate:NSDate&,&distance:Double,&distanceUnit:HKUnit&,&kiloCalories:Double,
&&completion:&(&(Bool,&NSError!)&->&Void)!)&{
&&&&//&1.&Create&quantities&for&the&distance&and&energy&burned
&&&&let&distanceQuantity&=&HKQuantity(unit:&distanceUnit,&doubleValue:&distance)
&&&&let&caloriesQuantity&=&HKQuantity(unit:&HKUnit.kilocalorieUnit(),&doubleValue:&kiloCalories)
&&&&//&2.&Save&Running&Workout
&&&&let&workout&=&HKWorkout(activityType:&HKWorkoutActivityType.Running,&startDate:&startDate,&endDate:&endDate,&duration:&abs(endDate.timeIntervalSinceDate(startDate)),&totalEnergyBurned:&caloriesQuantity,&totalDistance:&distanceQuantity,&metadata:&nil)
&&&&healthKitStore.saveObject(workout,&withCompletion:&{&(success,&error)&->&Void&in
&&&&&&if(&error&!=&nil&&)&{
&&&&&&&&//&Error&saving&the&workout
&&&&&&&&completion(success,error)
&&&&&&else&{
&&&&&&&&//&Workout&saved
&&&&&&&&completion(success,nil)
}这段代码做了什么呢?让我们一行一行地分析:与你之前创建BMI类型的身体素质信息一样,创建两个身体素质类型的对象,分别设置为距离和能量类型,注意使用double类型的数据以及选择合适的单位。使用起止时间、持续时间以及你刚刚创建好的代表距离和消耗的能量的身体素质信息来创建一个HKWorkOut对象,然后通过调用HKHealthKit Store的saveObject方法来将健康信息保存到Store中,结果信息或者是错误信息将传到completion回调中。现在你需要在Workouts视图控制器中调用该方法,打开WorkoutsTableViewController.swift然后找到unwindToSegue()方法,当你在新的Workout界面按下Done的时候就会调用该方法。将下面这一行:println("TODO:&Save&workout&in&Health&Store")替换为:if&let&addViewController:AddWorkoutTableViewController&=&segue.sourceViewController&as?&AddWorkoutTableViewController&{
//&1.&Set&the&Unit&type
var&hkUnit&=&HKUnit.meterUnitWithMetricPrefix(.Kilo)
if&distanceUnit&==&.Miles&{
&&hkUnit&=&HKUnit.mileUnit()
//&2.&Save&the&workout
self.healthManager?.saveRunningWorkout(addViewController.startDate!,&endDate:&addViewController.endDate!,&distance:&addViewController.distance&,&distanceUnit:hkUnit,&kiloCalories:&addViewController.energyBurned!,&completion:&{&(success,&error&)&->&Void&in
&&if(&success&)
&&&&println("Workout&saved!")
&&else&if(&error&!=&nil&)&{
&&&&println("\(error)")
}首先,创建一个合适的单位对象,用户通过分段控件(segment control)设置distanceUnit的值,从而选择距离单位的类型。这段代码检查distanceUnit的值来决定使用合适的HKUnit。创建完单位之后调用saveRunningWorkoutMethod()方法来保存这些健康信息,包括开始日期、结束日期、持续时间以及能量消耗。编译并运行,点击 + 按钮,像下面视图中展示的那样填入数据。哇!26.2英里(42.195千米),而且是两小时零一分钟之内,我想你刚刚在编码的过程中打破了马拉松世界记录。你真是个天才!完成之后点击Done,如果一切顺利,你将在Xcode的控制台中看到如下信息:Workout&saved!太棒了!你的健康信息已经成功地被保存到HealthKit Store中了,如果你想的话你可以重复刚才的操作来添加更多的健康信息。查询健康信息如果你运行你的应用,然后进入Workouts视图控制器,你不会看到任何之前你在视图中创建好的健康信息。你需要加入一些代码来读取并且展示这些信息。为了能够读取到这些信息,你需要创建一个HKSampleQuery对象,然后执行这个查询来获取数据。这与之前读取身高和体重的代码将会非常类似,为什么试着自己写一下呢?在HealthManager.swift中创建一个方法,利用HKWorkoutActivityType类型来查询健康信息,将结果按照起始日期降序的顺序排好序,在completion回调中获取返回结果。使用如下方法声明:func&readRunningWorkOuts(completion:&(([AnyObject]!,&NSError!)&->&Void)!)内部实现:readRunningWorkOuts的实现:打开HealthManager.swift然后添加这个方法:func&readRunningWorkOuts(completion:&(([AnyObject]!,&NSError!)&->&Void)!)&{
&&//&1.&Predicate&to&read&only&running&workouts
&&let&predicate&=&&HKQuery.predicateForWorkoutsWithWorkoutActivityType(HKWorkoutActivityType.Running)
&&//&2.&Order&the&workouts&by&date
&&let&sortDescriptor&=&NSSortDescriptor(key:HKSampleSortIdentifierStartDate,&ascending:&false)
&&//&3.&Create&the&query
&&let&sampleQuery&=&HKSampleQuery(sampleType:&HKWorkoutType.workoutType(),&predicate:&predicate,&limit:&0,&sortDescriptors:&[sortDescriptor])
&&&&{&(sampleQuery,&results,&error&)&->&Void&in
&&&&&&if&let&queryError&=&error&{
&&&&&&&&println(&"There&was&an&error&while&reading&the&samples:&\(queryError.localizedDescription)")
&&&&&&completion(results,error)
&&//&4.&Execute&the&query
&&healthKitStore.executeQuery(sampleQuery)
}这段代码与你之前读身高和体重的代码非常类似:首先创建一个谓词对象,HKQuery提供了一个方法:predicateForWorkoutsWithWorkoutActivityType()来创建查询锻炼信息用到的谓词。通过使用HKWorkoutActivityType.Running参数来指定你希望查询的是跑步类型的锻炼信息。如果你想查询其他类型的锻炼信息,例如骑行、游泳,你只需要在创建该谓词的时候改变查询类型即可。创建一个排序标识符来让结果信息按照日期降序排列。创建HKSampleQuery对象,调用executeQuery()方法来获得结果。你需要将健康信息展示到列表中,所以你要调用该方法并实现UITableView的数据源协议,所以,接下来打开WorkoutsTableViewController.swift。你需要在该类中创建一个数组类型的属性来保存所有的健康信息,将这一行代码添加到WorkoutsTableViewController顶部声明其他属性的附近:var&workouts&=&[HKWorkout]()然后,添加该方法,作用是当视图刚刚出现时读取健康信息:public&override&func&viewWillAppear(animated:&Bool)&{
&&super.viewWillAppear(animated)
&&healthManager?.readRunningWorkOuts({&(results,&error)&->&Void&in
&&&&if(&error&!=&nil&)
&&&&&&println("Error&reading&workouts:&\(error.localizedDescription)")
&&&&&&println("Workouts&read&successfully!")
&&&&//Kkeep&workouts&and&refresh&tableview&in&main&thread
&&&&self.workouts&=&results&as&[HKWorkout]
&&&&dispatch_async(dispatch_get_main_queue(),&{&()&->&Void&in
&&&&&&self.tableView.reloadData()
}这里调用了你刚刚创建好的方法readWorkouts。当收到结果后,将结果保存到workouts中,然后在主线程中刷新列表数据。现在,你需要添加列表的数据源协议中的方法,在WorkoutsTableViewController中添加tableView:numberOfRowsInSection方法的实现:public&override&func&tableView(tableView:&UITableView,&numberOfRowsInSection&section:&Int)&->&Int&{
&&return&&workouts.count
}这很直接明了,当列表询问有多少行时,你只需要返回你从Store中读到的健康信息的数量即可。现在是时候填充列表的cell了,你需要实现在列表的数据源协议中的方法tableView:cellForRowAtIndexPath,将如下代码添加到WorkoutsTableViewController类中:public&override&func&tableView(tableView:&UITableView,&cellForRowAtIndexPath&indexPath:&NSIndexPath)&->&UITableViewCell&{
&&let&cell&=&tableView.dequeueReusableCellWithIdentifier("workoutcellid",&forIndexPath:&indexPath)&as&UITableViewCell
&&//&1.&Get&workout&for&the&row.&Cell&text:&Workout&Date
&&let&workout&&=&workouts[indexPath.row]
&&let&startDate&=&dateFormatter.stringFromDate(workout.startDate)
&&cell.textLabel!.text&=&startDate
&&//&2.&Detail&text:&Duration&-&Distance&
&&//&Duration
&&var&detailText&=&"Duration:&"&+&durationFormatter.stringFromTimeInterval(workout.duration)!
&&//&Distance&in&Km&or&miles&depending&on&user&selection
&&detailText&+=&"&Distance:&"
&&if&distanceUnit&==&.Kilometers&{
&&&&let&distanceInKM&=&workout.totalDistance.doubleValueForUnit(HKUnit.meterUnitWithMetricPrefix(HKMetricPrefix.Kilo))
&&&&detailText&+=&distanceFormatter.stringFromValue(distanceInKM,&unit:&NSLengthFormatterUnit.Kilometer)
&&&&let&distanceInMiles&=&workout.totalDistance.doubleValueForUnit(HKUnit.mileUnit())
&&&&detailText&+=&distanceFormatter.stringFromValue(distanceInMiles,&unit:&NSLengthFormatterUnit.Mile)
&&//&3.&Detail&text:&Energy&Burned&
&&let&energyBurned&=&workout.totalEnergyBurned.doubleValueForUnit(HKUnit.jouleUnit())
&&detailText&+=&"&Energy:&"&+&energyFormatter.stringFromJoules(energyBurned)
&&cell.detailTextLabel?.text&=&detailT
&&return&cell
}解释一下上面的代码:这段代码获得当前这一行的健康信息,然后将起始日期格式化并展示在cell中的text lable上。为了将日期格式化,这里使用了之前在初始工程中为你创建好的NSDateFormatter类。通过距离和消耗的能量来定义展示在detail label中的字符串。距离信息以英里或者千米的形式展示出来,这取决于用户的选择(被保存在distanceUnit属性中)。获取距离的double类型的值,然后基于该属性的值传入一个合适的距离单位。接下来,使用NSDistanceFormatter类,传入合适的单位,调用stringFromValue:unit方法,将距离信息格式化为本地字符串。对于该条健康信息的持续时间,使用一个NSDateComponentsFormatter类对象。所有这些格式转换器都是在初始工程中为你预先创建好的。使用NSEnergyFormatter将消耗的能量也转换为字符串,该字符串最终将被展示到detail label中。编译并运行该app,导航到Workouts页面,现在你应该能在列表中看到之前储存好的健康信息了。酷!你已经如期将所有的健康信息展示出来了。现在,点击分段控件,检验一下,距离以英里或以千米为单位来展示,取决于你的选择。如果你打开Health应用,你不会在任何地方找到这些信息,它就是这样设计的,因为Health应用只展示数据采样信息,并不会展示我们的健康信息。然而,你是可以让用户看到这些关于健康的信息的,你只需要将它们与一些采样信息关联起来即可。一款健康管家应用如果不带有健康与锻炼的信息,就好比一教练机没有警报装置一样。因此你应该将这些数据结合起来。把采样信息添加到健康信息中作为最后一步,你将把距离和消耗的能量这些采样信息添加到健康信息中。打开HealthManager.swift然后前往saveRunningWorkout(),在成功执行的回调闭包中,将下面这两行://&Workout&saved
completion(success,nil)替换为://&if&success,&then&save&the&associated&samples&so&that&they&appear&in&the&HealthKit
let&distanceSample&=&HKQuantitySample(type:&HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning),&quantity:&distanceQuantity,&startDate:&startDate,&endDate:&endDate)
let&caloriesSample&=&HKQuantitySample(type:&HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned),&quantity:&caloriesQuantity,&startDate:&startDate,&endDate:&endDate)
self.healthKitStore.addSamples([distanceSample,caloriesSample],&toWorkout:&workout,&completion:&{&(success,&error&)&->&Void&in
&&completion(success,&error)
})到现在,你可能对这些代码已经非常熟悉了,甚至可能到了你会认为你在做重复的事情的地步了。但是为了让这些更加清晰,这里做一下解释:第一步中,创建了两个quantity sample类型的对象,一个用DistanceWalkingRunning类型来代表跑步的距离。另一个用ActiveEnergyBurned类型来代表消耗的卡路里,然后调用HealthKit Store的方法addsamples:ToWorkout将这两个数据添加到健康信息中。编译并运行该应用,添加一到两条健康信息,然后关掉应用。既然这些健康信息已经和距离以及消耗的能量的数据关联起来了,你就可以在Health应用中看到它们了。打开Health应用,前往Health Data栏,在这里选择Fitness选项,然后选择Walking+Running Distance或者Active Calories来检查一下数据是否保存到那里了。你将会看到类似如下界面:太棒了!现在你已经有获得最重要的健康信息并将其保存到HealthKit Store中的能力了。现在该干什么?从你可以下载包含这篇教程中所有代码的工程。!重要!:如果你想使用上面的示例工程,在使用HealthKit之前需要进行一些设置,因为该工程绑定了一个示例用Bundle ID,你需要将其修改为你自己的Bundle ID,选择你的开发团队,然后将Target栏中Capabilities菜单下的HealthKit的开关由OFF变为ON。详见上述“开始”部分和“授权与许可”部分。但愿本篇教程能够就HealthKit的基础概念给你一些对认识与了解,让你明白怎么样在自己的应用中使用HealthKit。要了解更多关于HealthKit的相关知识,这里有一些相关资源:2014年Apple的WWDC视频:关于HealthKit的,你应该确保你的应用遵守这些官方的Guidelines。在浏览过这些文档和视频之后,你应该准备好前往HealthKit更深入的方面,然后对本篇的这个应用做一些改善。例如,你可以添加一些新的类型的数据采样信息或者是健康信息,使用HKStatisticsQuery计算统计结果,或者通过HKObserverQuery来观察Store中信息的改变。我希望你能喜欢这篇教程,和以前一样,如果你有任何问题或者评论,请参与下方的讨论!(本文为CocoaChina组织翻译,本译文权利归译者所有,未经允许禁止转载。)
微信扫一扫
订阅每日移动开发及APP推广热点资讯公众号:CocoaChina
您还没有登录!请或
点击量3431点击量3370点击量2753点击量2667点击量2080点击量1736点击量1648点击量1632点击量1590
&2018 Chukong Technologies,Inc.
京公网安备89HealthKit开发教程:用Swift编写个健康应用!
发表于 17:50|
来源Ray Wenderlich|
作者Ernesto García
摘要:HealthKit是iOS 8中的新的API,它提供了一种优雅的方式来获取和存储用户的健康数据。在本篇HealthKit教程中,你不仅能学到许多关于HealthKit的知识,更能创建一个简单地记录用户信息的App。
个人特征与采样信息(Characteristics and Samples)在这一部分,你将会学习到:怎么样读取用户的个人特征信息?怎么样读写不同种类的数据采样信息?所有有趣的事都发生在ProfileViewController,在这里你会读到用户的特征(生日、年龄、血液类型)并且查询身高和体重数据。在那之后,你将会用这些数据进行一次计算(在这里,BMI代表Body Mass Index,身体质量指数)。并且将计算出来的数据保存到Store中。注意:身体质量指数(BMI)被广泛地应用于表示身体肥胖程度,由一个人的身高和体重经过一个公式计算而来,详情请点击。读取特征信息在你读取用户的特征信息之前,你需要确保在HealthKit Store中是有信息存在的,因此你需要先填充一些数据。打开在你的设备或者模拟器上的Health应用,选择Health Data栏,然后在列表中选择Me,然后点击Edit,添加生日、性别和血液类型的信息。随便输入一些信息,甚至是你耍点小聪明,填上以前状态下的信息或者是Kitty的信息也没问题。你下一步的任务是搭建框架然后读入这些信息。返回到Xcode,打开HealthManager.swift,将下面的方法加到HealthManager类的底部。func readProfile() -& ( age:Int?,
biologicalsex:HKBiologicalSexObject?, bloodtype:HKBloodTypeObject?)
var error:NSError?
var age:Int?
// 1. Request birthday and calculate age
if let birthDay = healthKitStore.dateOfBirthWithError(&error)
let today = NSDate()
let calendar = NSCalendar.currentCalendar()
let differenceComponents = NSCalendar.currentCalendar().components(.YearCalendarUnit, fromDate: birthDay, toDate: today, options: NSCalendarOptions(0) )
age = differenceComponents.year
if error != nil {
println("Error reading Birthday: \(error)")
// 2. Read biological sex
var biologicalSex:HKBiologicalSexObject? = healthKitStore.biologicalSexWithError(&error);
if error != nil {
println("Error reading Biological Sex: \(error)")
// 3. Read blood type
var bloodType:HKBloodTypeObject? = healthKitStore.bloodTypeWithError(&error);
if error != nil {
println("Error reading Blood Type: \(error)")
// 4. Return the information read in a tuple
return (age, biologicalSex, bloodType)
}该方法从Store中读入用户的特性信息,以一个元组的形式返回,它的工作方式是:调用dateOfBirthWithError()来从HKHealthStore中读取生日,下一行进行日历计算来确定年份。biologicalSexWithError()来确定性别。血液类型是从bloodTypeWithError()中读入的。最后,所有的信息以元组的形式返回。如果你现在编译并运行,你无法从UI上看出个人特征的数据有任何改变,因为你至今都没有为这个应用打开Store以及共享数据的入口。打开ProfileViewController.swift并找到updateProfileInfo()。当你点击按钮“Read HealthKit Data”时你需要调用这个方法,因此将下面这一行:println("TODO: update profile Information")替换为:let profile = healthManager?.readProfile()
ageLabel.text = profile?.age == nil ? kUnknownString : String(profile!.age!)
biologicalSexLabel.text = biologicalSexLiteral(profile?.biologicalsex?.biologicalSex)
bloodTypeLabel.text = bloodTypeLiteral(profile?.bloodtype?.bloodType)这段代码调用了你刚刚创建好的readProfile()方法,然后在UI方面将文本放到了合适的Label中。有趣的是,biologicalSexLiteral和bloodTypeLiteral并不是Healthk的方法,它们仅仅是两个便捷方法——还记得我提过吗?——基于血液类型和性别的数值来返回一个字符串。现在你的应用中,特征信息与Store已经可以互相交互了,现在编译然后运行你的app。前往Profile&BMI视图,点击“Read HealthKit Data”,你会看到tableView中得数据展示了你刚才在Health应用中输入的数据。太棒了!你成功地从HealthKit Store中读到了用户的特征信息。查询采样信息现在你讲读取用户的身高和体重,然后基于这些数据计算BMI数值,最后一并展示到视图中。要从Store中读取特征之外的信息你需要使用一条查询。查询的基类是HKQuery,这是一个抽象类,能够实现每一种查询目标。为了读取身体素质信息,你需要创建一条HKSampleQuery。要创建一条查询,你需要:指明你需要查询的信息的种类(例如:身高或者体重)一个可选的NSPredicate来指明查询条件(例如起止日期),以及一个NSSortDescriptors数组,来告诉Store怎么样将结果排序。一旦你有了一条查询,就可以调用HKHealthStore的executeQuery()方法来获得结果。注意:如果你对Core Data熟悉,你可能会注意到一些共同点:一个HKSampleQuery非常类似于NSFetchResult来查询实体类型,也是由你提供断言和排序描述,然后让对象上下文去执行查询并获得结果。你需要在一个普通的方法中发起一段查询,来获取所有数据采样信息种类的最近一部分的信息,这包括了身高和体重,因为你想展示的是最近刚刚测量得到的结果。打开HealthManager.swift然后将下面的方法添加到HealthManager类中:func readMostRecentSample(sampleType:HKSampleType , completion: ((HKSample!, NSError!) -& Void)!)
// 1. Build the Predicate
let past = NSDate.distantPast() as NSDate
= NSDate()
let mostRecentPredicate = HKQuery.predicateForSamplesWithStartDate(past, endDate:now, options: .None)
// 2. Build the sort descriptor to return the samples in descending order
let sortDescriptor = NSSortDescriptor(key:HKSampleSortIdentifierStartDate, ascending: false)
// 3. we want to limit the number of samples returned by the query to just 1 (the most recent)
let limit = 1
// 4. Build samples query
let sampleQuery = HKSampleQuery(sampleType: sampleType, predicate: mostRecentPredicate, limit: limit, sortDescriptors: [sortDescriptor])
{ (sampleQuery, results, error ) -& Void in
if let queryError = error {
completion(nil,error)
// Get the first sample
let mostRecentSample = results.first as? HKQuantitySample
// Execute the completion closure
if completion != nil {
completion(mostRecentSample,nil)
// 5. Execute the Query
self.healthKitStore.executeQuery(sampleQuery)
}要得到最近的信息,你构建了一段查询,指明排序方式为按日期降序。此时最接近的应该是查询返回结果的第一条。由于(大多数情况下)你只需要第一条信息,你使用limit来限制返回信息的数量为1.这相比较于返回全部的结果然后从中舍弃而言节省了时间和资源。让我们深入到查询的内部工作中去一探究竟:这里使用predicateForSamplesWithStartDate(_:endDate:options)来创建了一个日期并基于该日期创建一个谓词。注意:这里通过日期作为过滤条件只是一个示范,并不是必须要用这样的谓词,而且这个谓词是可以被设置为nil的。创建排序描述符,表明返回的结果按照开始日期降序排序。因为你只需要最新的数据,将limit限制为1.构建查询对象,传入查询类型、谓词、限制以及排序描述符。当查询完成之后,将调用completion闭包并返回读入的数据。最后,执行该查询。现在你需要在UI中调用这个方法,打开ProfileViewController.swift将下面属性的声明添加到ProfileViewController中:var height, weight:HKQuantitySample?你将使用这两个HKQuantitySample类型的属性来从HealthStore中获得身高和体重的数据。现在,找到updateWeight方法,将下面这一行:println("TODO: update Weight")替换为:// 1. Construct an HKSampleType for weight
let sampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)
// 2. Call the method to read the most recent weight sample
self.healthManager?.readMostRecentSample(sampleType, completion: { (mostRecentWeight, error) -& Void in
if( error != nil )
println("Error reading weight from HealthKit Store: \(error.localizedDescription)")
var weightLocalizedString = self.kUnknownS
// 3. Format the weight to display it on the screen
self.weight = mostRecentWeight as? HKQuantityS
if let kilograms = self.weight?.quantity.doubleValueForUnit(HKUnit.gramUnitWithMetricPrefix(.Kilo)) {
let weightFormatter = NSMassFormatter()
weightFormatter.forPersonMassUse =
weightLocalizedString = weightFormatter.stringFromKilograms(kilograms)
// 4. Update UI in the main thread
dispatch_async(dispatch_get_main_queue(), { () -& Void in
self.weightLabel.text = weightLocalizedString
self.updateBMI()
});让我们一段一段地分析:首先你指明了希望通过quantityTypeForIdentifier(从HKSample中)查询的数据采样信息的类型,然后将与体重类型相关联的标识符HKQuantityTypeIdentifierBodyMass传入。然后,使用这些类型作为参数来调用你刚刚在HealthManager中定义的方法,通过该方法返回体重类型的信息。在completion闭包中,使用doubleValueForUnit来得到千克为单位的体重数值,然后使用NSMassFormatter将该值转换为本地化的字符串。在主线程中更新UI界面,展示体重信息。HealthKit使用内部单独的一个线程,因此,确保所有更新UI的操作都在主线程上进行是非常重要的。同时你调用了一个方法叫做updateBMI——这是包含在初始项目中的一个方法,来计算并展示BMI(身体质量指数)。那个新的NSMassFormater是什么?你会在你刚刚添加上去的代码中发现这个新的类,尽管它不是HealthKit的一部分,但却十分有关联。iOS8提供了这个以及其他的格式转换器,例如图片方面的NSLengthFormatter和NSEnergyFormatter。它们将数量转换为字符串,并把用户所处位置也考虑在内。当你使用它们的时候,你不需要自己本地化字符串或者配置当前位置的单位转换。转换器会来处理这些细节。例如,你正在使用千克单位,即时你的系统不是公制配置的,转换器也会自动将其转换为合适的单位。现在,你需要为身高做同样的事,找到方法updateHeight(),将下面这行:println("TODO: update Height")替换为:// 1. Construct an HKSampleType for Height
let sampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)
// 2. Call the method to read the most recent Height sample
self.healthManager?.readMostRecentSample(sampleType, completion: { (mostRecentHeight, error) -& Void in
if( error != nil )
println("Error reading height from HealthKit Store: \(error.localizedDescription)")
var heightLocalizedString = self.kUnknownS
self.height = mostRecentHeight as? HKQuantityS
// 3. Format the height to display it on the screen
if let meters = self.height?.quantity.doubleValueForUnit(HKUnit.meterUnit()) {
let heightFormatter = NSLengthFormatter()
heightFormatter.forPersonHeightUse =
heightLocalizedString = heightFormatter.stringFromMeters(meters);
// 4. Update UI. HealthKit use an internal queue. We make sure that we interact with the UI in the main thread
dispatch_async(dispatch_get_main_queue(), { () -& Void in
self.heightLabel.text = heightLocalizedString
self.updateBMI()
})正如你所看到的,这段代码几乎与读取体重时的代码一致,但是有两个值得注意的不同点:首先,身高类型是由与身高数据类型相关联的标识符HKQuantityTypeIdentifierHeight来构建的,以此来允许你读取身高方面的数据。第二,这里使用了NSLengthFormatter来获取对应身高数值的本地化的字符串。NSLengthFormatter本身就是用来获取本地化的长度的字符串。现在你将用你刚刚从HealthKit Store中读取到的身高和体重来计算BMI(身体质量指数)并且将这些数据展示到屏幕上。打开ProfileViewController.swift并找到updateBMI()方法。将下面这一行:println("TODO: update BMI")替换为:if weight != nil && height != nil {
// 1. Get the weight and height values from the samples read from HealthKit
let weightInKilograms = weight!.quantity.doubleValueForUnit(HKUnit.gramUnitWithMetricPrefix(.Kilo))
let heightInMeters = height!.quantity.doubleValueForUnit(HKUnit.meterUnit())
// 2. Call the method to calculate the BMI
= calculateBMIWithWeightInKilograms(weightInKilograms, heightInMeters: heightInMeters)
// 3. Show the calculated BMI
var bmiString = kUnknownString
if bmi != nil {
bmiLabel.text =
NSString(format: "%.02f", bmi!)
}这段代码做了什么呢?具体来说:使用方法doubleValueForUnits()来获得身高和体重的double类型的数据,也是在这里你指明你想要的单位。注意:HKUnit提供了一种方法来构建所有类型的单位,这里你用克来转换体重,用米来转换身高,你必须十分小心,确保使用了一致的单位。因为如果要求的单位与数据的类型不相匹配的话,会抛出一个异常。例如,想把体重数值转换为距离单位是不会起作用的。通过调用calculateBMIWithWeightInKilograms()来计算BMI,这是初始项目中附带的一个工具方法,通过身高和体重来计算BMI。在合适的Label中展示BMI数值。因为BMI仅仅是一个数字,你不需要任何转换器来转换它。注意:如果你没有在HealthKit Store中添加一些供app读入的数据的话,你会被绊住的。如果你还没有做,你至少应该添加一些身高和体重的数据。现在,编译并运行app,前往Profile & BMI界面,点击“Read Health Data”,如果你已经在Health应用中添加了一些身高和体重的数据,那么你会看到类似如下输出:酷!你刚刚从HealthKit Stroe中读到了你的第一份数据采样的信息并且使用它们计算了BMI。
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章

我要回帖

更多关于 四年级下册解决问题训练 的文章

 

随机推荐