デートが苦手なエンジニアでも、女性をエスコートできるようになるかもしれないライフハック

今年も彼女が出来ませんでした。
かれこれ2年ほど彼女がいません。
いや、クリスマスまでにできる可能性は、まだあるんじゃないか？

#彼女が出来ない理由を考える
・顔がブサイク ➡︎ これはどうしよもできない。
・ファッションセンスがない ➡︎ 今地味に頑張ってる。
・よく歩くのが速いと言われる ➡︎ これは改善できるんじゃね？

###彼女が再び出来た時に備えて、歩行速度を改善しよう
そうしましょう。そうしましょう。
デートがうまくいかなかったら嫌ですもんね。

#今回用いたもの
・CoreMotionFramework...センサーへのアクセス
・AudioToolboxFramework...バイブレーションを動かすため

今回はお手軽にiPhoneのセンサーを使って移動ステータスを判定して、走っていると判定されたらバイブレーションで警告するという簡単なアプリケーションで、歩行改善を狙います。

##iPhone5s以降から歩行情報など手軽に取得できるように
端末のセンサーなどから歩行した歩数や「歩いている」「走っている」といった歩行ステータスを簡単に取得できるようになりました。
これによって、従来位置情報を基にしたロガーに加え、歩行情報や階段の上り下りなどの情報も含めてより精度の高いライフログアプリの開発も可能となってきています。
（標準のヘルスケアアプリなんかも同じ仕組みのはず)

ただし、ライフログのデータが取得できるのは搭載のチップに左右されますので今回掲載しているSampleCodeではiOS8以降かつiPhone5S以降の環境でしか動きません。動作チェックはiPhone6でしか行ってないので5sで上手くいくか見てない。。。。
(ちなみにiPhone5s以前だとCoreMotionFramework経由で取得出来る項目は、加速度とジャイロのみしかありません。)

##CMPedometerとCMMotionActivityManager
iOS8からCoreMotionFrameworkに追加された歩数関連のデータを取得出来るAPIです。
iOS7に追加されていたCMStepCunterは既にDeprecatedとなっていますので、注意です。

今回、掲載しているCodeではiPhone6以降のみ対応と書きましたが、これは搭載されているモーションチップの違いによるものです。
iPhone5sはM7、iPhone6以降はM8が搭載されています。

M7とM8の違いですが、M7は加速度センサー、ジャイロセンサー、磁気センサーの処理をまとめて行えるチップ。
M8はM7の機能に気圧計が追加されたものだそうです。


#サンプルコード
```Swift:ViewController
import UIKit
import CoreMotion
import AudioToolbox

class ViewController: UIViewController {
    
    let pedometer = CMPedometer()
    let activity = CMMotionActivityManager()
    var timer: Timer!
    
    var vibrateFlg:Bool = false

    @IBOutlet weak var dataLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // CMPedometerの確認
        if(CMPedometer.isStepCountingAvailable()){
            self.pedometer.startUpdates(from: NSDate() as Date) {
                (data: CMPedometerData?, error) -> Void in
                DispatchQueue.main.async(execute: { () -> Void in
                    if(error == nil){
                        //エア彼女と歩いた歩数を表示させる
                        let steps = data!.numberOfSteps
                        self.dataLabel.text = "\(steps)"
                    }
                })
            }
        }
        
        //CMMotionActivityManagerの確認
        if CMMotionActivityManager.isActivityAvailable() {
            activity.startActivityUpdates(to: OperationQueue.current!,
                withHandler: {activityData in
                DispatchQueue.main.async(execute: { () -> Void in
                    if(activityData?.stationary == true){
                        print("止まっている")
                        self.vibrateFlg = false
                    } else if (activityData?.walking == true){
                        print("あるいている")
                        self.vibrateFlg = false
                    } else if (activityData?.running == true){
                        print("走ってる")
                        self.vibrateFlg = true
                    } else if (activityData?.automotive == true){
                        print("乗り物")
                        self.vibrateFlg = false
                    }
                })
                
            })
        }
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        timer = Timer.scheduledTimer(timeInterval: 1.0,
                                     target: self,
                                     selector: #selector(self.vibrateLoop),
                                     userInfo: nil,
                                     repeats: true)
        timer.fire()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(true)
        timer.invalidate()
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func vibrateLoop () {
        if vibrateFlg {
            AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
        }
    }
}
```
歩数の取得は、CMPedometer。歩行状態の取得には、CMMotionActivityManagerの各パラメータの状況を基に判定しています。
CMMotionActivityManagerの各パラメータは下記の4つです。
「stationary」....静止状態
「walking」.......歩行状態
「running」.......走っている時
「automotive」....乗り物での移動時

これらは全て真偽値で帰ってきますが、1つだけTrueになるのではなく条件によっては複数の項目で、
Trueになるということもあるようなのです。（手元の環境では、確認できていません)

今回のSampleでは、走っているときのステータス「running」がTrueの時に、端末のバイブレーションが動き続きます。

非常にシンプルなサンプルとなりました。

#使ってみて...
判定が思ったより精密で、「早歩き」程度では走っているという判定にならず...

だめじゃん！！

ただ、ドキドキして走っちゃうこともあるよね！！！
そういうときに使ってみてね！！

#最後に
歩行データなど取り扱えることを知り、勉強がてら軽く自分用のサンプルとして作ってみました。
思ったよりも簡単に歩行データが取得できることからもライフログ系のアプリ開発の敷居は、結構下がっているかなと。
ただ、データの更新間隔がまばらなので即時性や高精度となると限界があるかなというのが今回軽く触った印象です。
何よりも位置情報使うより端末の消費電力がそんなに高くないっていうのが魅力的ですね。
常にスマートフォンを携帯しているこのご時世なので、1日のざっくりしたログ収集は簡単にできるのは間違いなさそうです。

会社で使う機会はなさそうですが....

#最後の最後に
まだ諦めていない。クリスマスまで、まだ日にちはあるんだ...

2017年1月1日追記
まぁお察しの通りできませんでしたので、2017年も頑張ります。