単位換算アプリの作成(swift)


#はじめに

###航空の世界は単位が多い
![83BCF875-DFFB-47F3-91A3-ADFCF12B7C51.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261100/126eb816-369b-c3eb-0145-7d5e01f73900.jpeg)
>写真はwikipediaより

航空業界は日本では普段使用しない単位を多用します。
また使用する機種によっても単位が違いますので換算が必要です。
(例えば、アメリカ製のヘリコプターは燃料の単位にlbsを使うが
　日本製のヘリコプターは燃料にkgを使用します）

航空単位の例

| | 航空(米) | 通常(日本) |
|:-:|:-:|:-:|
| 高度  |  ft |  m |
| 重量 | lbs  | kg  |
| 距離 |  NM | km  |
| 速度  | kt  |  km/h |


###単位を間違えたことによる事故も発生している
[ユナイテッド航空173便燃料切れ墜落事故](https://ja.wikipedia.org/wiki/ユナイテッド航空173便燃料切れ墜落事故)

上記リンクは燃料の単位を間違えたことにより、燃料不足で墜落した例です。

###専用の換算ツールが欲しい！
単位の変換は大きなヒューマンエラーになるのです。
専用のアプリを作りました。

#航空単位換算アプリ（概要）
![スクリーンショット 2021-10-02 13.51.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261100/df00036a-1fc8-d913-9016-3785818f12f3.png)

![calculator概要.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261100/c0d8c793-b3da-dc7e-d481-657cf3c1e101.jpeg)


電卓方式で数値を入力すると、同時に換算値を表示してくれます。
換算する単位はピッカーから選択します。
結果をtableViewに保存する機能もつけました。

#①必要なラベルや変数を定義

```swift:sample
    var preNumberScreened :Double = 0 //入力値
    var resultNumberScreened :Double = 0 //換算結果の値
    var resultNumberScreenedRounded :Double = 0 //換算結果の値(少数点第3位以下切り捨て）
    var calculationIsActive :Bool = true //計算機をアクティブに
    var pickerData :[String] = ["lbs → kg","kg → lbs","ft → m","m → ft","海里 → km","km → 海里","kt → km/h","km/h → kt"]
    var saveArray :[String] = [] //ユーザーデフォルトに保存する用の空配列
    var unit :Double = 0 //換算のかけ値

    @IBOutlet weak var preNumberLabel: UILabel! //入力値ラベル
    @IBOutlet weak var resultNumberLabel: UILabel! //換算結果ラベル
    @IBOutlet weak var preDegree: UILabel! //入力値単位ラベル
    @IBOutlet weak var resultDegree: UILabel! //換算結果単位ラベル
     
    @IBOutlet weak var resetButton: UIButton! //リセットボタン
    @IBOutlet weak var pickerView: UIPickerView!
    @IBOutlet weak var saveButton: UIButton!
    @IBOutlet weak var readButton: UIButton!
```

#②計算機能の作成

```swift:sample
    func calc(){
        //入力値を換算する
        resultNumberScreened = preNumberScreened * unit
        resultNumberScreenedRounded = floor(resultNumberScreened * 100) / 100 //小数点以下第３位切り捨て
        resultNumberLabel.text = String(resultNumberScreenedRounded)
    }
```

変数「unit」は単位換算用の変数です。
換算する単位に応じて変化させます。
例えばft→mなら　unit = 0.304　

〜参考メモ〜
round() -> 四捨五入
floor() -> 切り捨て
ceil()  -> 繰り上げ

#③pickerによる単位の選択

```swift:sample
//pickerの設定
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return pickerData.count
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?{
        return pickerData[row]
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int){
        
        //pickerの選択に応じて入力値単位ラベルと換算結果単位ラベルの表示を変更する
        switch row{
        case 0:
            preDegree.text = "lbs"
            resultDegree.text = "kg"
            unit = 0.4535
            code = 0
            
        case 1:
            preDegree.text = "kg"
            resultDegree.text = "lbs"
            unit = (1/0.4535)
            code = 1
            
        case 2:
            preDegree.text = "ft"
            resultDegree.text = "m"
            unit = 0.3048
            code = 2
            
        case 3:
            preDegree.text = "m"
            resultDegree.text = "ft"
            unit = (1/0.3048)
            code = 3
            
        case 4:
            preDegree.text = "海里"
            resultDegree.text = "km"
            unit = 1.852
            code = 4
            
        case 5:
            preDegree.text = "km"
            resultDegree.text = "海里"
            unit = (1/1.852)
            code = 5
            
        case 6:
            preDegree.text = "kt"
            resultDegree.text = "km/h"
            unit = 1.852
            code = 6
            
        case 7:
            preDegree.text = "km/h"
            resultDegree.text = "kt"
            unit = (1/1.852)
            code = 7
            
        default:
            break
        }
        
        //再計算
        calc()
        
    }
```

switchを利用して選択した単位に応じて換算用の変数unitの値の変更や表示する単位ラベルの変更を行っています。


#④数字ボタンを押した時の挙動の機能

```swift:sample
//数字ボタンを押した時の挙動の機能
    @IBAction func numbers(_ sender: UIButton) {
        
        if calculationIsActive == true{
            preNumberLabel.text = String(sender.tag-1)
            preNumberScreened = Double(preNumberLabel.text!)!
            calculationIsActive = false
        }else if calculationIsActive == false{
            preNumberLabel.text = preNumberLabel.text! + String(sender.tag-1)
            preNumberScreened = Double(preNumberLabel.text!)!
        }
        
        //計算
        calc()
        
    }
```

すでに数字が入力されていたら、その数字の隣にボタンで押した数字を追加する処理を書いてます。
入力後すぐに換算結果は反映されます。

#⑤リセット機能

```swift:sample
//リセット機能
    func reset(){
        preDegree.text = "lbs" //デフォルト
        resultDegree.text = "kg" //デフォルト
        preNumberScreened = 0
        resultNumberScreened = 0
        preNumberLabel.text = String(preNumberScreened)
        resultNumberLabel.text = String(resultNumberScreenedRounded)
        unit = 0.453 //lbs->kg
        calculationIsActive = true
        // ピッカーを更新
        pickerView.selectRow(0, inComponent: 0, animated: true)
        pickerView.selectedRow(inComponent: 0)
        //再計算
        calc()
    }
    
    //リセットボタン
    @IBAction func reset(_ sender: Any) {
        reset()
    }
```

入力値をゼロに変更して再計算するとともに、入力値・換算値ラベルと単位ラベルをデフォルトに戻します。

#⑥結果保存機能

```swift:sample
//ユーザデフォルトへの保存機能
    @IBAction func saveToUserdefaults(_ sender: Any) {
        
        //Int型をStringに変換（入力値と換算値）
        memoryValue1 = String(preNumberScreened)
        memoryValue2 = String(resultNumberScreened)
        
        //ピッカーからコードを抽出して、コードに合わせた単位を取得する
        //あまりスマートな処理ではない
        switch code{
        case 0:
            memoryValue4 = "lbs"
            memoryValue5 = "kg"
        case 1:
            memoryValue4 = "kg"
            memoryValue5 = "lbs"
        case 2:
            memoryValue4 = "ft"
            memoryValue5 = "m"
        case 3:
            memoryValue4 = "m"
            memoryValue5 = "ft"
        case 4:
            memoryValue4 = "海里"
            memoryValue5 = "km"
        case 5:
            memoryValue4 = "km"
            memoryValue5 = "海里"
        case 6:
            memoryValue4 = "kt"
            memoryValue5 = "km/h"
        case 7:
            memoryValue4 = "km/h"
            memoryValue5 = "kt"
        default:
            break
        }
        
        
        //文字を合体
        matchValue = "\(memoryValue1)[\(memoryValue4!)] → \(memoryValue2)[\(memoryValue5!)]"
        
        //ユーザーデフォルト保存用の空配列に合体させた文字を追加(）
        saveArray.append("\(matchValue)")
        
        //userDefaultsに配列を保存
        UserDefaults.standard.set(saveArray, forKey: "1")
        
        //保存ダイアログ
        let savedDialog = UIAlertController(title: "換算結果を保存しました", message: "\(matchValue)", preferredStyle: .alert)
        
        savedDialog.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        
        self.present(savedDialog, animated: true, completion: nil)
        
    }
```

![スクリーンショット 2021-10-02 14.33.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261100/c434e4d8-2bc1-b11a-e97b-5e60a1eb3332.png)


#⑦保存した値をtableViewで表示

こちらの記事を参照
[userDefaultsに保存した値をTableViewで表示する(swift)](https://qiita.com/PearlEarringMinion/items/b103d2b9e404a34505f1)



#まとめ
使用する単位がいつも同じなのであれば、普通の換算ソフト・アプリより便利かもしれません。

#全ソースコード(github)
[https://github.com/PearlEarringMinion/calculator](https://github.com/PearlEarringMinion/calculator)