iOSアプリ開発初学者の学習（1日目）

# 概要

初学者が躓いたところと参考になったページ（URL）をメモ。わからなかったことは可能な限り全部書きます。

# 留意事項

PHP, Javascript, C#、Javaはそれなりに触ってきました。
C#とJavaは数年触ってないので、触れてましたと言った方が良いかも。

# 環境

macOS 10.14.2
Swift 4.2.1
XCode 10.1

# 学習として作るもの

## BMI管理アプリ（iOS）

### 機能
BMIを算出（式: kg / ( m x m ））
BMIの履歴を管理できる（一覧表示）

### 画面構成

BMI計算画面と履歴表示画面の2画面で構成する

### 技術要件

TableViewを使うこと

# 躓いたところ

## storybordって何？

画面を追加したり、画面にオブジェクトを追加したり、画面やオブジェクトの設定（定義）を変更できたりする。特にコードを書かなくても画面遷移させるぐらいなら実装できる。すごい。storybordは分割できるみたい。分割したstorybordはつなぐこともできる。機能単位で切り分けて開発する時とか便利そう。
storybordを使うのが標準的なのかはわからない。アプリの仕様によっても違うとは思う。

## storybordにオブジェクトの配置ができない

調べると画面右下にあるよって皆言うけど無いよ(｀；ω；´)

以下で解決しました。
[Xcode10(beta)でのUI作成ができない](https://teratail.com/questions/141912)
cmd + shift + L

## 配置したオブジェクトとコードとの紐付けができない

オブジェクトにユニークな名前付けてそれとコードを紐付けるんでしょ！的な発想でしたが、上手く行かず。

以下で解決。
[[Swift]TextFieldを使って簡単な足し算アプリを作ってみる](https://qiita.com/sasagin/items/0c51a3c6d9b82618c82a)
多分ドラッグ＆ドロップじゃなくてもできそうだけど結局どうやるのかよくわからなかった。

## 変数とかプロパティの後ろに付ける「!」 is 何

以下を参考にして理解はできていない（多分自分の努力不足）。
[【swift】変数によく付いている「！」や「？」（ビックリマーク・クエスチョンマーク）の説明](https://qiita.com/sasagin/items/0b255c790c4c3aecc630)
?はPHPの型宣言でも同じようなことをやってるのでわかるんだけど?の方が今ひとつわからない。
Unwrapping自体を理解しないといけない気がする。

## 入力制限とバリデーションってどうやってやるの？

TextFieldからそのまま値を持ってきてキャストとかこわい。ってことで入力制限とバリデーションを実装したいけどどうやってやるのかわからなかった。一旦後回し。

## storybordで画面遷移どうやってやるの？

こちらを参考にしながらトライ。
[(初心者向け)Swift3.0で初アプリ - 次画面を追加してみる](https://qiita.com/egplnt/items/2806aa6b88a966a82f8c)
ボタンタップしたら画面遷移したいけど右クリックメニューでSent EventのTouch Down選ぶとボタンと次の画面の紐付けが行えない(｀；ω；´)
オブジェクトを選んだままドラッグ＆ドロップしたらオブジェクトが次の画面に行ってしまう...。
ここで「画面遷移はEventじゃなくね？」って思いついてTriggered seguesのactionで試してみると上手く行った(｀・ω・´)
Triggered seguesが何だかはわかっていない。せぐえす...せ...せぐうぇい（小声

## ローカルストレージにデータを保存する

画面遷移のボタンをタップ時にデータをローカルストレージに保存してから画面遷移させたい。
まずはローカルストレージにデータを追加してみる。userDefaultsって単語は聞いたことあるのでそこから検索検索ゥ！
画面遷移の方法はわかったので一旦削除しておく（ローカルストレージの実装が終わったらまたやってみる）。
連想配列（身長、体重、BMI）を連想配列（key: 日付）で保存したい。

連想配列の色々参考にさせて頂きました。
[Swift4.0でDictionaryが大幅にパワーアップした](https://qiita.com/hanawat/items/341a6f7843f4e19780b5)

userDefaultsに入れる時に参考にさせて頂きました。
[userDefaultsを使った配列の保存・取得・操作](https://qiita.com/k_eita/items/d36b4cffd9fc6e133c70)

割とスムーズに行くなぁと思ってたらuserDefaults.setでエラー発生(´・ω・｀)
AppDelegateでThread 1: signal SIGABRTとのこと...なんぞこれ。ググる。
storybordでエラー出てる箇所を直せば良いって記事が多く見つかるが、エラー出てないん...。
こういう時はログだ、ログ。

```
[User Defaults] Attempt to set a non-property-list object (
        {
        bmi = "8.569445";
        height = "<UITextField: 0x7fd5fd078200; frame = (129 73; 117 30); text = '12'; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x6000001fb900>; layer = <CALayer: 0x600000faa9c0>>";
        weight = "<UITextField: 0x7fd5fd850c00; frame = (129 143; 117 30); text = '1234'; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x6000001ff4e0>; layer = <CALayer: 0x600000ff8280>>";
    }
) as an NSUserDefaults/CFPreferences value for key test
```

なるほど（わかってない）。もうちょっと見てみる。

```
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object (
        {
        bmi = "8.569445";
        height = "<UITextField: 0x7fd5fd078200; frame = (129 73; 117 30); text = '12'; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x6000001fb900>; layer = <CALayer: 0x600000faa9c0>>";
        weight = "<UITextField: 0x7fd5fd850c00; frame = (129 143; 117 30); text = '1234'; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x6000001ff4e0>; layer = <CALayer: 0x600000ff8280>>";
    }
) for key test'
```

とりあえず`Attempt to set a non-property-list object`と`NSInvalidArgumentException`で調べれば解決の糸口が見えそう。ちなみに該当箇所のコードは以下。

```swift
@IBAction func didAddBmiData(_ sender: Any) {
    let userDefaults = UserDefaults.standard
    var bmiData: [Any] = userDefaults.array(forKey: "bmiData") ?? []
    let addData: Dictionary = [
        "height": self.height,
        "weight": self.weight,
        "bmi": self.bmiVal
        ] as [String : Any]
    bmiData.append(addData)
    print("userDefaults.set")
    userDefaults.set(bmiData, forKey: "test")
}
```

何となくuserDefaultsにsetするのを配列じゃなくて文字列にしてみる。上手く行った...っぽい。ってことは入れる値の問題？？？引き続きググる。
んーよくわからない。如何ともし難い。一回普通に配列を作って入れてみる。

```swift
let temp:[String] = ["hoge", "piyo"]
userDefaults.set(temp, forKey: "test")
```

こんな感じに修正して実行。また入ったっぽい...Dictionaryをそのまま入れてみる。

```swift
let temp:[String : String] = ["hoge" : "piyo"]
userDefaults.set(temp, forKey: "test") // 空っぽ！
```

入った。ように見えてこれ入ってない(´・ω・｀)んんん？

ここで次案件のスクラムイベントの作成と仕様整理作業がカットインしたので、続きはまた今後。jsonにして保存とかすれば良いのかな...。
TableView使うところまでいけなかった。