WWDC -Introducing HealthKit

不同的健康应用需求大致可以分为三种

1.统计分析 (Statistical Analysis)
2.允许用户输入设备(Enter Information)
3.允许来自第三方的设备数据(Application From Health Providers)
为此,apple开发了Healthkit来处理这些需求

1. Data in HealthKit

在不同的国家,对同一个概念有着不同的度量单位。所以在HealthKit中,提出了HKUnit的概念。他就是为了帮助开发者做单位转换的。HKUnit代表了一个在度量标准或单位系统中的特定单位

1.1 HKUnit
HKUnit *g = [HKUnit gramUnit]; //克
HKUnit *dL = [HkUnit literUnitWithMetricPrefix:HKMetricPrefixDeci];//分升
HKUnit *gPerdL = [g unitDivideByUnit:dL]; // 克/分升  g/dL
//对于复杂的组合单位,也可以使用这种方式创建
HKUnit *gPerdL = [HKUnit unitFromString:@"g/dL"];
1.2 HKQuantity

他可以用于进行单位转换

HKUnit *gramUnit = [HKUnit gramUnit];
HKQuantity *grams = [HKQuantity quantityWithUnit:gramUnit doubleValue:20]; //20克
double kg = [grams doubleValueForUnit:[HKUnit unitFormString:@"kg"]];//转换为了0.02kg

但是不是所有的单位都是可以这样进行转换的,如果转化为一个不兼容的单位时,就会报错。所以我们可以使用下面的方法进行预判断。

BOOL kgCompatible = [grams isCompatibleWithUnit:[HKUnit unitFromString:@"kg"]]; // YES
BOOL kgCalComtible = [grams isCompatibleWithUnit:[HKUnit kilocalorieUnit]];  // NO

也就是说HKQuantity就是带有单位的数量值

1.3 HKObjectType

Object types代表了HealthKit中的所有数据类型。在HealthKit中有超过60种类型,大多数的类型都会整合到他自己类中。所有的这些类,都是继承于HKObjectType。所有的类分为两个基本大类。(1)HKCharacteristicType:他代表一种不会改变的一些类型,比如生日、性别等。(2)HKSampleType:代表会随时间改变的类型,它们能在一定特定的时间点里获取的到类型的样本。在这个类型下面又分为两种类型
1>HKQuantityType ,比如血压
2>HKCategoryType,代表可以分类的类型,比如睡眠分析。具体结构如图1

图1.png

KHObjectType的创建:每一种类型都有的他自己的identifier。当然你不能创建自己的objectType和对应的identifier。但是我们可以理解下他的构造规则。

HKQuantityTypeIdentifierHeartRate
HKQuantityTypeIdentifier:代表他属于那种类型的数据
HeartRate :代表他的名字

只要你有了某个类型的identifier,你就可以使用构造方法进行创建

+(HKQuantityType *)quantityTypeForIdentifier:(NSString   *)identifier;
+(HKCategoryType *)categoryTypeForIdentifier:(NSString *)identifier;
+(HKCharacteristicType *)characteristicTypeForIdentifier:(NSString *)identifier;
//显然三种构造方法,对应了三种不同的类型
1.4 HKObject

在HealthKit中的所有存储数据都是HKObject的子类,具体结构如下图2


图2

HKQuantitySample有quantityType和quantity两个属性。qantityType代表了这个对象数据属于那种类型,quantity代表了具体的数值和单位。quantity的单位和quantityType需要匹配。每一个quantity type都对应了一种特定的单位。如果没有对应,则会抛出异常。如图3

图3.png

HKCategorySample和HKQuantitySample类似,他也有categoryType代表他属于那种类型的数据,同时他有value值。这里要记住categoryType是一种可以的数值都是可以被枚举出来的。所以,每种类型都有一套对应的枚举值,value值必须对应其中的一个数值,如果一种出现了异常的数值,就会报错。见图4

图4.png

这些类型都是继承自HKSample,因为sample一种可以在特定时间进行取样的的数据,所以,他有startDate和endDate。对于有些数据,比如果你想获取体重这种及时性非常高的值(总不能获取一段时间的体重吧),所以他的startDate和endDate是相同的,而对于那种读取一定时间内的数值的数据类型,他们的startDate和endDate会不一样。每种sample也都有sampleType属性,他的实际类型和子类的type类型相同。如图5

图5.png

以上者这些都是继承于HKObject类型,每个Objec类型都有一个UUID类型的属性,他是这个sample的唯一标识。他也有source属性,他记录了数据的来源。metadata对象是NSDictionary类型的属性,所以可以在里面存放任何你想存放的数据,这个属性主要是为了扩展准备的。苹果也开发者准备了一些metadatakey。如图6

图6.png

Create an HKObject

NSString * identifier = HKQuantityTypeIdentifierBodyTemperature;
HKquantityType * tempType = [HKObjectType quantityTypeForIdentifier:identifier];
HKQuantity * myTemp = [HKQuantity quantityWithUnit:                 [HKUnit degreeFahrenheiUnit] doubleValue:98.6];
NSDictionary *meta = @{HKMetadataKeyBodyTemperatureSensorLocation : @(HKBodyTemperatureSensorLocationEar)};
HKQuantitySample *temperatureSample = [HKQuantitySample quantitySampleWithType:tempType
                                                                  quantity:myTemp
                                                                 startDate:[NSDate date]
                                                                   endDate:[NSDate date]
                                                                  metadate:meta];

</br>

2. Save Data

self.store = [[HKHealthStore alloc] init];
...
HKQuantitySample *mySample = [self newSample];
[self.store saveObject:mySample withCompletion:^(BOOL success,NSError *error){
if (success) {
  NSLog(@"object saved!");
}
}];

</br>

3 Ask For Data

3.1 Characteristics

前面讲到,HKCharacteristicType是一种基本不变的数据类型,所以我们可以直接去获取对应的数据,比如,生日、血型等

NSError *error;
NSDate *dateOfBirth = [self.store dateOfBirthWithError:&error];
3.2 Queries

所有的Query都继承自HKQuery

@interface HKQuery
//注定要检索的数据类型
@property (readonly) HKSampleType *sampleType
//过滤返回的数据
@Property (readonly) NSPredicate *predicate
@end
创建Predicate的几种方式
//1.直接是使用构造方法
[NSPredicate predicateWithFormat:@"%K > %@",     HKPredicateKeyPathQuantity,weight];

//2.更加简便的方式
NSPredicateOperatorType greaterThan =     NSGreaterThanPredicateOperatorType;
[HKQuery perdicateForQuantitySampleWithOperatorType:greaterThan
                                       quantity:weight];
3.2.1 HKSampleQuery

Limit:每个query都有个limit值,他指定了请求返回值的数量,如果你不想限制检索的结果,你可以设置limit值为HKObjectQueryNoLimit。
Sort Order:决定返回的数据的排列顺序的数组。

//Code demo
HKQuantityType *bloodSugar = ...
NSString *endKey = HKSampleSortIdentifierEndDate;
NSSortDescriptor *endDate = [NSSortDescriptor sortDescriptorWithKey:endKey ascending:NO];
HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:bloodSugar 
                                                  perdicate:nil
                                             sortDescriptor:@[endDate]
                                              resultsHandle:^(HKSampleQuery * query,
                                                              NSArray *results,
                                                              NSError *error)
{
    HKQuantitySample *sample = [results lastObject];
    NSLog(@"Sample: %@",sample);
}]
3.2.2 HKObserverQuery

他会监听数据库中的数据改变。所以当一个新的数据被添加或移除的时候都会被调用。

HKQuantityType *bloodSugar = ...
HKObserverQuery *query;
query = [HKObserveQuery alloc]   initWithSampleType:bloodSugar
                              perdicate:nil
                              updateHandler:^(HKObserverQuery *query,
                                                  HKObserverCompletionHandler handler,
                                              NSError *error)
{
  NSLog(@"Updated");
}
3.2.3 HKAnchoredObectQuery

Anchor是你见的最后一条数据,当anchor为0时,表示还没有设置anchor,当每一次回调的时候会返回给你一个新的anchor

self.lastAnchor = 0
...
HKQuantityType *bloodSugar = ...
HKAnchoredObjectQuery *query;
query = [[HKAnchoredObjectQuery alloc] initWithType:bloodSugar 
                                     perdicate:nil
                                        anchor:self.lastAnchor
                                         limit:HKObjectQueryLimit
                              completionHandler:^(HKAnchoredObjectQuery *query,
                                                                NSArray *results,
                                                                NSUInter newAnchor,
                                                                  NSError *error)
{
  self.lastAnchor = newAnchor;
}];

</br>

4. executeQuery

@interface HKHealthStore: NSObject
- (void)executeQuery:(HKQuery *)query;
- (void)stopQuery:(HKQuery *)query;
@end

stopQuery方法可以在任何时候调用,他回取消当前的检索操作,并阻止其回调。你可以调用任意次数的stopQuery,但是只能在上一个query结束前,调用一次query。通常情况下,检索执行一次就会停止。但是像ObserverQuery这样的long runing query(这里还是原文比较有味道)需要手动去停止。
</br>

5.Asking for Statistics

HKStatistics
一个HKStatistics对象是各种统计数据的集合,比如sum、min、max 和 average。
你可以统计所有的数据,或者只统计特定来源的数据
⚠️注意,Statstics只对quantity类型的数据有效。
这里将数据分为离散数据(discrete)和聚合数据(cumulative)
离散数据:比如身高、体重、血压等
聚合数据:比如步数、燃烧的脂肪量

区别:前者是单次取样获取的有效数据,后者是持续取样的到一段时间的累加的数据

HKStatisticsQuery

HKQuantityType *stepCount = ...
NSPredicate *today = ...
HKStatisticsOptions sumOptions =       HKStaticsOptionCumulativeSum;
HKStatisticsQuery *query;
query = [HKStatisticsQuery alloc] initWithQuantityType:stepCount
                              quantitySamplePerdicate:today
                              options:sumOptions
                              completionHandler:^(HKStaticsQuery *query,
                                                  HKStatics *result,
                                                  NSError *error)
{
  HKQuantity  *sum = [result sumQuantity];
} 

HKStaticsCollectiion

@interface HKStatisticsCollection:NSObject
- (NSArray *)statistics
- (HKStatistics *)statisticsForDate:(NSDate *)date;
- (void)enumberateStatisticsFromDate:(NSDate *)startDate
                          toDate:(NSDate *)endDate
                           block:(void(^)(HKStatistics *stats,BOOL *stop))block;
@end

</br>

6.Privacy and Permissions

//请求授权
- (void)requestAuthorizationToShareTypes:(NSSet *)typesToShare
                           readTypes:(NSSet *)typesToRead
                          completion:(void(^)(BOOL success, NSError *error))completion;                      
//监测授权情况                
typedef NS_ENUM(NSInteger, HKAuthorizationStatus) {
  HKAuthorizationStatusNotDetermined = 0,
  HKAuthorizationStatusSharingDenied,
  HKAuthorizationStatusSharingAuthorized,
}

- (HKAuthrizationStatus)authorizationStatusForType:    (HKObjectType *)type

</br>

7.Localization

NSFormatter 能帮助开发者进行本地化处理

NSnumberFormatter
NSDateFormatter
NSByteCountFormatter

NSMassFormatter
NSLengthFormatter
NSEnergyFormatter
//Code demo
NSMassFormatter *formatter = [[NSMassFormatter alloc] init]
formatter.forPersonMassUse = YES;

HKQuantity * weight = ...
double weightKg = [weight doubleValueForUnit:[HKUnit unitFromString:@"kg"]];
NSString *localizedString = [formatter stringFromKilograms:weightInKg];

总结:

本文从健康应用出发,阐述了HealthKit的方方面面,包括数据的单位、储存、获取等,最后apple还未开发者提供了本地化方案。文本是2014年WWDC Session 203 的笔记,更加详尽的内容请点击这里(https://developer.apple.com/videos/play/wwdc2014/203/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容