Using Sleep Analysis in HealthKit with Swift--譯文

今天碍侦,睡眠革命已經(jīng)成為一種時尚惯退,并且人們比以往任何時候都想了解他們睡眠的時間,更想分析收集自己睡眠時間趨勢透露出來的信息咒锻,先進的技術(shù)冷冗,硬件,手機把這個看似不斷增長的項目帶入了一個新的時代惑艇。

蘋果提供了一種很酷并且安全的方式來與用戶個人健康信息進行通信蒿辙,并且通過內(nèi)置的健康A(chǔ)pp對這些信息進行安全的存儲。你不僅可以使用HealthKit建立一個健身的應(yīng)用程序滨巴,同時這個框架也允許你訪問睡眠質(zhì)量等數(shù)據(jù)思灌。
在本教程中,我會快速的向你介紹這個HealthKit框架恭取,并且掩飾如何創(chuàng)建一個基于睡眠數(shù)據(jù)分析的簡單應(yīng)用泰偿。

Introduction---前言介紹

HealthKit框架提供了一個結(jié)構(gòu)用于將數(shù)據(jù)以加密的數(shù)據(jù)庫的方式保存在 HealthKit store中,你可以使用HKHealthStore類訪問此數(shù)據(jù)庫蜈垮, iPhoneApple Watch都有他們自己的HealthKit store耗跛,健康數(shù)據(jù)可以在iPhoneApple Watch之間同步裕照。然而為了節(jié)省空間,Apple Watch上過早的數(shù)據(jù)會被周期性的清除调塌。HealthKit框架和Health 應(yīng)用并不能在iPad上使用晋南。

如果你想創(chuàng)建一個基于健康數(shù)據(jù)的iOS或者watchOS應(yīng)用,HealthKit將是一個強大的工具羔砾。它的設(shè)計目的就是在更廣泛的資源上來管理數(shù)據(jù)负间,自動的合并基于用戶偏好的不同來源的數(shù)據(jù)。應(yīng)用程序可以訪問各個資源的原始數(shù)據(jù)并且可以合并數(shù)據(jù)本身姜凄,不僅可以針對身體的測量政溃,健身或營養(yǎng)情況,該數(shù)據(jù)也可以用于睡眠質(zhì)量等分析态秧。

在接下來的文章中玩祟,我將告訴你如何使用HealthKit framework在iOS上保存和訪問睡眠分析數(shù)據(jù),當(dāng)然屿聋,方法同樣適用于watchOS的應(yīng)用空扎。值得注意的是,本教程使用Swift 2.0 和 Xcode 7.編寫润讥,所以確保你的Xcode版本在7.0以上转锈。

在開始之前,請下載啟動項目并解壓縮楚殿,我已經(jīng)創(chuàng)建了一個基本功能的用戶界面撮慨,當(dāng)你運行啟動這個項目,你會看到一個計時器脆粥,顯示你按下按鈕之后經(jīng)過的時間砌溺。

Working with the HealthKit Framework---HealthKit框架的使用

我們應(yīng)用程序的目的是利用StartStop按鈕來實現(xiàn)保存睡眠分析信息和取出數(shù)據(jù),要使用HealthKit必須在一開始的時候授權(quán)你的應(yīng)用程序訪問HealthKit:打開你的Xcode->project->target ,打開HealthKit功能变隔。如下圖

接下來规伐,需要創(chuàng)建一個HKHealthStore的實例,在你的ViewControlle類中粘貼如下代碼:

let healthStore = HKHealthStore()```
稍后匣缘,我們會使用HKHealthStore實例來訪問`HealthKit store`

正如之前提到的猖闪,HealthKit必須經(jīng)過授權(quán)才可以訪問并控制他們的健康數(shù)據(jù),所以你必須先請求用戶的許可才可以訪問(讀/寫)用戶的睡眠分析數(shù)據(jù)肌厨。要做到這一點培慌,第一步首先到導(dǎo)入內(nèi)置的HealthKit框架( HealthKit framework)并且更新你的`viewDidLoad`方法,代碼如下:

override func viewDidLoad() {
super.viewDidLoad()

let typestoRead = Set([
    HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis)!
    ])

let typestoShare = Set([
    HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis)!
    ])

self.healthStore.requestAuthorizationToShareTypes(typestoShare, readTypes: typestoRead) { (success, error) -> Void in
    if success == false {
        NSLog(" Display not allowed")
    }
}

}```

上面的代碼會提示用戶允許或者拒絕權(quán)限請求柑爸,在完成的block中可以對成功或失敗出錯進行處理吵护,并且也可以得到最終的結(jié)果。當(dāng)然用戶并不是必須或者一定會同意你的應(yīng)用程序所有的權(quán)限請求,所以你必須在程序中妥善的處理錯誤情況馅而。
但是出于測試目的祥诽,你必須選擇“允許”選項,授予應(yīng)用程序權(quán)限訪問設(shè)備上的健康數(shù)據(jù)用爪。如下圖:


Writing Sleep Analysis Data---寫入睡眠分析數(shù)據(jù)

首先原押,我們?nèi)绾尾拍塬@取睡眠分析數(shù)據(jù)呢胁镐?根據(jù)蘋果的官方文檔偎血,每個睡眠分析樣本只能有一個值,這個值代表用戶無論躺在床上還是已經(jīng)睡著了盯漂,HealthKit用兩個或者多個重復(fù)時間的樣本颇玷,通過比較這些樣本的開始和結(jié)束時間,應(yīng)用程序統(tǒng)計計算出來的一個值:

  • the amount of time it takes for the user to fall asleep

  • the percentage of time in bed that the user actually sleeps

  • the number of times the user wakes up while still in bed

  • the total amount of time spent both in bed and asleep

簡單來說就缆,按照下面的方法把分析得到的睡眠數(shù)據(jù)保存到HealthKit store:

1.我們需要定義對應(yīng)于開始時間和結(jié)束時間的兩個`NSDate`對象帖渠。

2.然后我們使用`HKCategoryTypeIdentifierSleepAnalysis`創(chuàng)建一個`HKObjectType`實例。

3.我們需要創(chuàng)建一個`HKCategorySample`類型的新對象竭宰,通常使用樣本的類別來記錄睡眠數(shù)據(jù)空郊。每個    樣本代表用戶躺在床上或者進入睡眠的時間段。所以我們會同時創(chuàng)建一個躺在床上的樣本和一個進入睡眠狀態(tài)的樣本切揭。

4.最后我們用`HKHealthStore`的`saveObject`方法來保存對象狞甚。

注意的是:對于樣本的類型,可以查看HealthKit Constants Reference

鏈接中的內(nèi)容是Objective-C版本廓旬,如果你要翻譯成swift版本哼审,這里是保存睡眠數(shù)據(jù)的代碼,請?zhí)砑拥?code>ViewController類中:

func saveSleepAnalysis() {
    
    // alarmTime and endTime are NSDate objects
    if let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) {
        
        // we create our new object we want to push in Health app
        let object = HKCategorySample(type:sleepType, value: HKCategoryValueSleepAnalysis.InBed.rawValue, startDate: self.alarmTime, endDate: self.endTime)
        
        // at the end, we save it
        healthStore.saveObject(object, withCompletion: { (success, error) -> Void in
            
            if error != nil {
                // something happened
                return
            }
            
            if success {
                print("My new data was saved in HealthKit")
                
            } else {
                // something happened again
            }
            
        })
        
        
        let object2 = HKCategorySample(type:sleepType, value: HKCategoryValueSleepAnalysis.Asleep.rawValue, startDate: self.alarmTime, endDate: self.endTime)
        
        healthStore.saveObject(object2, withCompletion: { (success, error) -> Void in
            if error != nil {
                // something happened
                return
            }
            
            if success {
                print("My new data (2) was saved in HealthKit")
            } else {
                // something happened again
            }
            
        })
        
    }
    
}```

上述方法在我們想要把睡眠分析數(shù)據(jù)保存到`HealthKit`的時候調(diào)用孕豹。
###Reading Sleep Analysis Data---讀取睡眠分析數(shù)據(jù)

要想獲取睡眠分析數(shù)據(jù)涩盾,需要創(chuàng)建一個`query`(查詢語句),首先定義一個`HKObjectType`類別`HKCategoryTypeIdentifierSleepAnalysis`,然后你還需要是用一個時間條件使用`startDate`和`endDate`(NSDate類型)來獲取檢索時間范圍內(nèi)的數(shù)據(jù)励背,你還需要創(chuàng)建一個`sortDescriptor`排序的檢索查詢以獲取所期望的數(shù)據(jù)春霍。
下面是檢索睡眠分析數(shù)據(jù)的示例代碼:

func retrieveSleepAnalysis() {

// first, we define the object type we want
if let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) {
    
    // Use a sortDescriptor to get the recent data first
    let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
    
    // we create our query with a block completion to execute
    let query = HKSampleQuery(sampleType: sleepType, predicate: nil, limit: 30, sortDescriptors: [sortDescriptor]) { (query, tmpResult, error) -> Void in
        
        if error != nil {
            
            // something happened
            return
            
        }
        
        if let result = tmpResult {
            
            // do something with my data
            for item in result {
                if let sample = item as? HKCategorySample {
                    let value = (sample.value == HKCategoryValueSleepAnalysis.InBed.rawValue) ? "InBed" : "Asleep"
                    print("Healthkit sleep: \(sample.startDate) \(sample.endDate) - value: \(value)")
                }
            }
        }
    }
    
    // finally, we execute our query
    healthStore.executeQuery(query)
}

}

用剛才的代碼查詢HealthKit獲得所有的睡眠分析數(shù)據(jù),然后降序排列叶眉,每個查詢語句都打印了`startDate`,`endDate`,`value`,上述代碼已經(jīng)設(shè)置了上限30天來檢索過去30天的樣本终畅,你也可以自定義方法來選擇你自己認為的開始和結(jié)束時間。
###App Testing---測試
對于上面的Demo竟闪,我使用NSTimer來顯示距離按下按鈕的時間离福,保存這個按鈕的開始和結(jié)束時間內(nèi)(NSDate對象)的睡眠分析數(shù)據(jù),在停止的方法里炼蛤,可以調(diào)用`saveSleepAnalysis()`和`retrieveSleepAnalysis()`方法來保存和獲取睡眠數(shù)據(jù)妖爷。

@IBAction func stop(sender: AnyObject) {
endTime = NSDate()
saveSleepAnalysis()
retrieveSleepAnalysis()
timer.invalidate()
}

在你的app里,你需要改變NSDate對象來選擇相應(yīng)的開始和結(jié)束時間(可能不相同)來保存躺在床上和進入睡眠狀態(tài)的值。
一旦更改了之后絮识,你就可以運行你的程序啟動定時器绿聘,,讓它運行幾分鐘之后按下停止按鈕次舌,打開Health app熄攘,你就會看到相應(yīng)的睡眠數(shù)據(jù)。如下圖:

![](http://upload-images.jianshu.io/upload_images/701353-6f7993c57e45bca8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

###Some Advices for HealthKit Apps---總結(jié)與建議
HealthKit蘋果設(shè)計這個框架的目的就是提供給開發(fā)者一個共享平臺彼念,用以分享或訪問用戶的數(shù)據(jù)挪圾,避免數(shù)據(jù)中可能的重復(fù)和不一致。蘋果的審核說明明確指出逐沙,使用了HealthKit并要求讀寫權(quán)限的但是對于數(shù)據(jù)使用沒有明確的示例和說明的話會被拒哲思。
保存假的或者不正確的數(shù)據(jù)到Health App也會被拒(悲劇)吩案,意味著對于計算不同的健康值你的算法不能太low棚赔,或者存在僥幸心理。就像本教程中睡眠分析計算那樣徘郭,你應(yīng)該嘗試使用內(nèi)置的傳感器數(shù)據(jù)讀取和處理任何參數(shù)靠益,以避免錯誤的計算數(shù)據(jù)。
有關(guān)完整的Xcode項目残揉,[看這里](https://github.com/appcoda/SleepAnalysis).


































最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胧后,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子冲甘,更是在濱河造成了極大的恐慌绩卤,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件江醇,死亡現(xiàn)場離奇詭異濒憋,居然都是意外死亡,警方通過查閱死者的電腦和手機陶夜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門凛驮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人条辟,你說我怎么就攤上這事黔夭。” “怎么了羽嫡?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵本姥,是天一觀的道長。 經(jīng)常有香客問我杭棵,道長婚惫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮先舷,結(jié)果婚禮上艰管,老公的妹妹穿的比我還像新娘。我一直安慰自己蒋川,他們只是感情好牲芋,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著捺球,像睡著了一般缸浦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上懒构,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天餐济,我揣著相機與錄音耘擂,去河邊找鬼胆剧。 笑死,一個胖子當(dāng)著我的面吹牛醉冤,可吹牛的內(nèi)容都是我干的秩霍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蚁阳,長吁一口氣:“原來是場噩夢啊……” “哼铃绒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起螺捐,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤颠悬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后定血,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赔癌,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年澜沟,在試婚紗的時候發(fā)現(xiàn)自己被綠了灾票。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡茫虽,死狀恐怖刊苍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情濒析,我是刑警寧澤正什,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站号杏,受9級特大地震影響婴氮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一莹妒、第九天 我趴在偏房一處隱蔽的房頂上張望名船。 院中可真熱鬧,春花似錦旨怠、人聲如沸渠驼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迷扇。三九已至,卻和暖如春爽哎,著一層夾襖步出監(jiān)牢的瞬間蜓席,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工课锌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留厨内,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓渺贤,卻偏偏與公主長得像雏胃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子志鞍,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容