SwiftでBMI計算アプリ作成


Swiftを使ってみたくて、勉強と健康管理ついでに作りました。
入力した値を公式に代入して答えを吐き出すだけの簡単なアプリです。
恐縮ながらやった事のメモを書いてみます。

## 環境
macOS Sierra 10.12.6
Xcode 8.3.3
Swift 4

## 工程
### Xcodeをインストールする
はじめにXcodeをインストールしておく。
要AppleID。
インターネットの環境によっては時間がかかるので注意する。
https://developer.apple.com/downloads/index.action

### Projectを作成する

Xcodeを起動する。
[Create a new Xcode Project]をクリックするか、[File] -> [New] -> [Project] をクリックする。

![スクリーンショット 2017-09-29 17.20.38.png](https://qiita-image-store.s3.amazonaws.com/0/178476/00492e58-d56d-88cc-4094-a1812c4ca10d.png)

今回は フレームワークなしでSingle View Application を作るのでそのままNextをクリックする。

![スクリーンショット 2017-09-29 17.23.39.png](https://qiita-image-store.s3.amazonaws.com/0/178476/3e644c53-87c8-50c9-4dc7-aeaaae406db9.png)

[Product Name] : 好きな名前を入力
[Organization Name] : わかりやすい名前を入力
[Organization Identifier] : 通常、持っているドメイン名などを逆にしたものをつける。必須項目。
３つを入力したら[Next]をクリックする。
保存場所を聞かれたら適当なフォルダを選択して[Create]をクリックする。

![スクリーンショット 2017-09-29 17.29.24.png](https://qiita-image-store.s3.amazonaws.com/0/178476/c5ccc94c-e2b2-f7eb-5354-44168b66c305.png)

### UIを作成する
一番左のカラムから[Main.storyboard]を選択する。

![スクリーンショット 2017-09-29 17.39.03.png](https://qiita-image-store.s3.amazonaws.com/0/178476/280686aa-0030-37cd-bdf8-f536add4e8a9.png)

二重丸の所を選択しておいて、右下の小さな検索窓にLabelと入力するとLabelというObjectが出て来くるので
それを真っ白なView Controller上にドラッグ＆ドロップする。
右上の[Text]の所で適切な名前に変更しておく。

![スクリーンショット 2017-09-29 17.49.00.png](https://qiita-image-store.s3.amazonaws.com/0/178476/8355ed0b-dcc5-15e6-239b-184c71adfc89.png)

この要領で目標の画面（下の画面）を目指す。
![スクリーンショット 2017-09-29 17.52.30.png](https://qiita-image-store.s3.amazonaws.com/0/178476/f1e3f106-b20f-f48a-a9f4-42a7f4d69398.png)


身長とcmの間にあるのは値を入力するので [Text Field]、「男」「女」「送信」 は [Button] 、その他は全て[Label]を使用。

### UIを接続する

作ったUIをソースコードに接続する。
接続するのはText FieldとButton、出力結果を表示するためのLabelで、計12個。

右上の○が重なったボタンをクリックしてエディタを右カラムに表示させる。
![スクリーンショット 2017-10-02 9.45.20.png](https://qiita-image-store.s3.amazonaws.com/0/178476/97f9a48b-439a-fbe7-90df-8c14426ad987.png)

接続したいUIを選択し、[control]を押しながら右カラムのエディタの上にドラッグ＆ドロップする。
吹き出しの中のフォームを次のとおりに埋めて[Connect] をクリックする作業を、接続したいUI分行う。（計12回）

**身長、体重、年齢のText Field**
Connection : Outlet
Name : わかりやすい名前
Type : UITextField
Storage : Weak

**男、女、送信のButton**
Connection : Action
Name : わかりやすい名前
Type : UIButton
Event : Touch Up Inside
Arguments : Sender

**結果表示用のLabel**
Connection : Outlet
Name : わかりやすい名前
Type : UILabel
Storage : Weak

これで右カラムのソースコードのclass内に9個の変数（`@IBOutlet weak var`）と
3個の関数（`@IBAction func`）が出来ていれば接続は完了。

### コードを書く
左カラムから[ViewController.swift]を選択してソースコードをメインカラムに表示させる。右カラムは邪魔なので消す。

ソースコードの概要は次の通り。
・ファーストビューの状態として結果表示用のLabelには何も表示しないようにする。
・男ボタンを押したら1を、女ボタンを押したら2をsex変数に代入する。
・送信ボタンを押したら、「身長」「体重」「年齢」「性別（男or女）」に入力された値を使って計算式に代入し、結果を結果表示用Labelに代入する。

できあがったコード（雑感は承知なのでに真面目なつっこみをしてはだめです…）

```swift
...

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var hight: UITextField!
    @IBOutlet weak var weight: UITextField!
    @IBOutlet weak var age: UITextField!
    @IBOutlet weak var bmi: UILabel!
    @IBOutlet weak var basalMetabolism: UILabel!
    @IBOutlet weak var calorie: UILabel!
    @IBOutlet weak var carbohydrate: UILabel!
    @IBOutlet weak var protein: UILabel!
    @IBOutlet weak var lipid: UILabel!
    var sex: Int!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        self.hight.keyboardType = UIKeyboardType.numberPad
        self.weight.keyboardType = UIKeyboardType.numberPad
        self.age.keyboardType = UIKeyboardType.numberPad
        sex = 0
        bmi.text = ""
        basalMetabolism.text = ""
        calorie.text = ""
        carbohydrate.text = ""
        protein.text = ""
        lipid.text = ""
    }
    
    @IBAction func male(_ sender: UIButton) {
        sex = 1
    }
    
    @IBAction func female(_ sender: UIButton) {
        sex = 2
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    @IBAction func calculate(_ sender: UIButton) {
        
        let doubleH = Double(hight.text!)
        let doubleW = Double(weight.text!)
        let intAge = Int(age.text!)

        bmi.text = calcBmi(doubleH!, doubleW!)
        
        let metabo = calcBasalMetabo(doubleH!, doubleW!, intAge!)
        let dairyCalorie = calcCalorie(metabo)
        
        basalMetabolism.text = metabo.description
        calorie.text = dairyCalorie.description
        carbohydrate.text = calcCarbohydrate(dairyCalorie)
        protein.text = calcProtein(doubleH!, doubleW!)
        lipid.text = calcLipid(dairyCalorie)
        
    }
    
    private func calcBmi(_ hight: Double,_ weight: Double) -> String {
        
        let h = hight / 100
        let w = weight
        
        var result = w / ( h * h )
        
        result = floor(result*10) / 10
        
        return result.description
        
    }
    
    private func calcBasalMetabo(_ hight: Double,_ weight: Double,_ age: Int) -> Double{
        
        var x: Double!
        var y: Double!
        var z: Double!
        var k: Double!
        let doubleAge = Double(age.description)
        
        if sex == 1 {
            x = 66
            y = 13.7
            z = 5.0
            k = 6.8
            
        } else if sex == 2 {
            x = 665
            y = 9.6
            z = 1.7
            k = 7.0
        } else {
            x = 1
            y = 1
            z = 1
            k = 1
        }
        
        let w = (y * weight)
        let h = (z * hight)
        let a = (k * doubleAge!)
        
        let result = x + w + h - a

        return result
        
    }
    
    private func calcCalorie(_ metabo: Double) -> Double {
        
        var result = metabo * 1.5
        
        result = floor(result*10) / 10
        
        return result
    }
    
    private func calcCarbohydrate(_ calorie: Double) -> String {
        
        let x = 50 * calorie
        
        var result = x / 400
        
        result = floor(result*10) / 10
        
        return result.description
    }
    
    private func calcProtein(_ hight: Double,_ weight: Double) -> String {
        
        return "50"
    }
    
    private func calcLipid(_ calorie: Double) -> String {
        
        let x = 20 * calorie
        
        var result = x / 900
        
        result = floor(result*10) / 10
        
        return result.description
    }

}
```

各計算式の参考：
[三大栄養素 | 日本人の食事摂取基準(2015年版)より | 栄養成分ナビ - グリコ](http://www.glico.co.jp/navi/e07.html)
[自分の基礎代謝量、BMI（肥満度）、１日の適正カロリー、目標心拍数を計算してみよう！](http://neutral-fat.com/tool/%E5%9F%BA%E7%A4%8E%E4%BB%A3%E8%AC%9D%E9%87%8F%E8%A8%88%E7%AE%97%E3%83%84%E3%83%BC%E3%83%AB/)
[推定エネルギー必要量 - 日本医師会](https://www.med.or.jp/forest/health/eat/01.html)

※ private func calcCalorie で基礎代謝に ×1.5してるのは労力の関係上運動量低に合わせた。
※ タンパク質の推奨摂取量が50固定なのはURL参考のため。（50をベタでreturn返してるのはつっこまない）

### ビルドする

できあがったコードでビルドできるはずなのでビルドする。
左上の再生マークをクリックしてビルドする。

できたー。
![スクリーンショット 2017-10-02 10.54.33.png](https://qiita-image-store.s3.amazonaws.com/0/178476/6924b347-c79f-07ec-3367-6b349f21f2e6.png)

![スクリーンショット 2017-10-02 12.13.45.png](https://qiita-image-store.s3.amazonaws.com/0/178476/785376fe-9ce5-2340-a64a-5381d85efb33.png)


33％縮小したので荒い。
例外処理してないから空欄のまま送信すると落ちる仕様。

## やってみて思ったこと
家にSwift2の本があったのですが関数が廃止になってたり名前が変わってたりと4になると変更がかなりありました。
公式のドキュメントを読むのが一番はやいかもなぁと思いましたが、体力の関係で全然読んでないため各所理解が乏しいままです。
今回の反省点として今後はドキュメントをちゃんと読もうと思いました。

UIを作るのはポチポチしてるうちに楽しくなってきて色々試したくなりました。

以上、至らない所が多々あったのですが、自分にとって新しい事が出来たので楽しんでSwiftに触れることができたとおもいます。
今後も色々発見を楽しみつつ触れ合って行きたいなぁというかんじです。