【初心者】swift4.2,Xcode10で画面遷移を作る

このシリーズについて

- 3月から勉強を始めた
- ド素人が
- 最近通い始めた謎のプログラミングスクールで学んだ情報を
- 自分の理解度を向上させるために
- アウトプットしていきます
- 自分の勉強が目的なので画像を貼ったり絵を書いたりする時間はないです
- 謎のスクールでは秘伝のソースをたくさん使って授業が行われています
- なので書いたコードをそのまま書けません
- つまりqiitaの「投稿者以外の人にとっても価値のある記事」に反する可能性があります
- ごめんなさい。


##今回やったことと、解決した疑問点
- ページ遷移させるアプリをつくる
    - モデル(Model)ってなんだ
    - コントローラ(Controller)ってなんだ
    - ビュー(View)ってなんだ
    - ストーリーボード(Storyboard)ってなんだ
    - クラス(class)ってなんだ
    - let varってなんだ
    - File's ownerってなんだ
    - 画面遷移ってどうやるんだ


##やることのイメージ
①コントローラーを2個作ります
②コントローラーと対になるようにビューを2個作ります
③コントローラーとビューを紐づけます
④最初のページ(ビューの方)にボタンを置きます
⑤ボタンをコントローラーに登場させます
⑥遷移先ページもコントローラーに登場させます
⑦ボタンを押したら遷移させるようにさせます
⑧ｳｺﾞｲﾀｱｱｱｱｱｱ

※「コード主体でストーリーボードもそこそこ使う」という書き方は一般的ではないと聞いたので、あまり参考にしないほうがいいと思います。あくまでアウトプットです


## 始める前に：モデルとかコントローラーとかビューについて
当たり前のように使われていたのでXcodeの仕様なのかと思ってググったら、”MVC"というプログラミングの考え方みたいですね。
それすら知らずにただコードを書いていたので、やっぱりアウトプットは大切ですね。

**View**
絵。
ユーザーが実際に見たり触ったりする見た目の部分

**Controller**
ゲームのコントローラーと一緒。
Aボタンを押したらジャンプするとかそういう指示をする

**Model**
わからん。
まだ授業で習ってません。

参考：MVCモデルについて
https://qiita.com/s_emoto/items/975cc38a3e0de462966a


## プロジェクトを作ろう！
早速Xcodeを触っていきましょう。
”Create a new Xcode project”から"Single View app"をつくります。それ以外の項目は何なのか私は知りません。
プロダクトネーム以外はすべてデフォルト。
そしてViewControllerを見てみましょう。

ドンッ

```swift:ViewController.swift
import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
}
```
うわああああわかんねえええ
でも頑張って理解していきます

```swift:ViewController.swift
import UIKit
```
UIKitというものを使えるようにしてくれるそうです。
UIKitはとりあえず必要らしいので残します

```swift:ViewController.swift
class ViewController: UIViewController {
}
```

ここでクラスというものが登場します。
下記参考サイトでは、たい焼きの型が”クラス”で、その型を使ってできるたい焼きそのものが”インスタンス”と紹介されています。

「私たい焼きは粒あんしか許さないので、クリームとか入るようにわざわざ型とか作って汎用性上げる必要ないです」ってひねくれていたのですが、よくよく考えると粒あん一種類しか作らないとしても型は必要なので、「クラス作って、そこからインスタンス作って」って流れは必須みたいです。(よくわかってない)

参考：“たい焼き”であま～く理解するJava文法と言語仕様 
https://www.atmarkit.co.jp/ait/articles/0803/12/news148.html


```swift:ViewController.swift
ViewController: UIViewController
```

このコロン(:)、怖いですね。
このコロンは「継承」ということをやっているようです。

「”ViewController”というクラスを今回作るけど、こいつは”UIViewController”という機能を継承してるから、おんなじことできるよー」ってことですね。

じゃあその"UIViewController"ってなんやねんって誰もが思うと思いますが、これはXcode様が我々下民に予め用意されてくださった機能のようです。右クリックして"Jump to Definition"をクリックするとUIKit内のUIViewControllerの定義を見ることができますが、全くわからないので見なくていいと思います。

参照：継承
https://tea-leaves.jp/swift/content/%E7%B6%99%E6%89%BF


```swift:ViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()
}
```

まずfuncですが、これは関数というものだそうです。
下のやつがめちゃくちゃ分かりやすいので下のやつ読んだらいいと思います（怠惰）
何行もある処理を何回も書くのはめんどくさいからviewDidLoadって先に関数にまとめちゃっておいて、viewDidLoadって書くだけで何行も書いたことにしちゃおうってことですね。

参考：関数
https://wp-p.info/tpl_rep.php?cat=swift-biginner&fl=r18

```swift:ViewController.swift
    override func viewDidLoad()
```
"override func"については下のやつが再度参考になります。
"viewDidLoad"というこれまたXcode様が用意してくださったコードを踏襲しています。

参照：継承
https://tea-leaves.jp/swift/content/%E7%B6%99%E6%89%BF


```swift:ViewController.swift
        super.viewDidLoad()
```
これまた上の継承に乗っています。super.をつけることによって、override funcの横にくっついてる親要素のviewDidLoad()をやるよ！と言っているわけですね。

つまりまとめると、
新しいクラス"ViewController"を作ります。
ViewControllerは基本的にはUIViewControllerと同じ機能を持ったクラスです。
ViewControllerはviewDidLoad()を継承した関数も格納していて、
その格納された関数内では、なんとviewDidLoad()だけが作動します。
ってことですね。

ここで、なんで親と子で同じviewDidLoadしか言ってないんだ？親子の友情を深めたいのか？という疑問が湧き上がってきたのですが、よくわかりません。
本当に動かすときにはsuper.viewDidLoad()の下の行にもなんか他の動作を追加するんですかね？わかりません。まあいいでしょう。

ちなみに、//以下の部分はコメントなので実際のコードに影響を及ぼしません。なので私には見えていません。

## ここから先は参考にならないかも
それでは、私の通っているスクールでは**"Import UIKit"以下全て消します。**

**そして秘伝のソースをぶち込みます。**

そのためこの先の説明が非常にあやふやになりますので、ここから参考資料としての質がこれまで以上に一気に落ちます。みなさんは秘伝のソースを持っていないのでとりあえずの流れだけ読み取ってもらえると嬉しいです。よろしくお願いいたします。

```swift:ViewController.swift
import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
}
```


## Controllerを作ろう
今回は画面を2つ作る必要があるので、
Command + Nで"Cocoa Touch Class"を2つ作成します。
クラス名は"TopViewController"と"NextViewController"で、下の選択部分はデフォルトのままで大丈夫です。

Cocoa Touch Classってなんだろうと思って下の参考ページを見たのですが、親切に選択項目によって良さげなデフォルトコードを差し込んでくれるようですね。

**ただ、私の場合はその親切さを秘伝のソースで流し去ります**
(だからあんまりCocoa Touch Classにする必要ないと思うんですが、なんででしょうかね。とりあえず左上にいるからですかね？)

参考：[Xcode]Cocoa Touch ClassとSwift Fileの違いはなに？
https://code-schools.com/cocoa-touch-class-or-swift-file/


とりあえず、Controller内には下のように書きます。
この"BaseViewController"が秘伝のソースらしく中身を読んでもさっぱりわかりません

```swift:TopViewController.swift
import UIKit
class TopViewController: BaseViewController {
}
```

## Viewを作ろう
Controllerをつくったら、次はView(xibファイル)も作ります。
Command + NでViewを作成します。名前は上と全く同じ。名前が"TopViewController"でもビューです。混乱しますね。

その後はFile's Ownerなるものを設定します。ビューを作成しただけでは、真っ白なキャンパスが宙ぶらりんになっているだけの状態です。なので、「私、このクラス様のビューなの…」とご主人の名前を彫ってあげないとアプリとして使える状態にならないようです。

クラス設定の手順は下の参考を見てください。スクリーンショットがたくさんで見やすいです。

"TopViewController"のFile's Owner(クラス)は"TopViewController"
"NextViewController"のFile's Owner(クラス)は"NextViewController"です。


参考：【Swift4】xibファイルでViewを作成してStoryboardで使用する方法
http://program-life.com/559

File's Ownerを設定したら、Outletsを設定します。
なんかFile's Ownerをクリックした状態で、Controlキーを押しながらドラッグすると線を引けます。
それでFile's Owner→View(すぐ下のやつ)に線を引くと…

"Outlets"
"view"

みたいな感じになります。
viewを選択します。
完了です。
何をやっているのか全くわかりません。
でも完了です。

多分下記が参考になるんだと思います。

参考：【Xcode/Swift】Action接続、Outlet接続の外し方（削除する方法）
https://pg-happy.jp/xcode-delete-action-outlet-connection.html

## ボタンを作ろう！
今回作りたいものはボタンを押したらページ遷移するアプリなので、ボタンを作る必要があります。

TopViewController から NextViewController にページ遷移させたいので
TopViewControllerのビューにボタンを載せます。

Shift + Command + Lで検索できるので、そこにbuttonと書き込むとボタンが出てくるのでそれをビューの好きなところにドラッグします。ボタンにはクラスを付与する必要はないです。

あとはXcode画面右上の丸が2個重なっているようなアイコンを押すと2画面表示ができるので、今作成したビューのボタンを、Controlキーを押しながら、TopViewControllerのコントローラーに載せます。

今回は、ボタンを押したら動く！を実現したいので、
connection は Action
name は 好きな名前(授業ではtouchedButtonでした)
type は UIButtonです。

するとこんなのが出ると思います。

 ```swift:TopViewController.swift
    @IBAction func touchedButton(_ sender: UIButton) {
    }
```

IBActionという物によってボタンが動きましたよーという動作をコントローラーが認識できるようになってくれます。

参考：IBOutletとIBAction：関連付けでラクラクパーツを配置しよう
http://iphone-app-program.com/newapp/iboutlet-and-ibaction/ibbas/

ボタンが動作した後は、funcから始まる先程の関数ですね。
「touchedButtonという機能を発動させるよー。機能は{}の中だよー」って感じです。

 ```swift:TopViewController.swift
    (_ sender: UIButton) {
    }
```

これはよくわかりません。とりあえずXcodeさんが勝手にやってくれてるってことは、ありがたくそのまま使わせてもらえばいいんじゃないでしょうか。
_をつけることによって、「第1引数の『外部引数名』の省略を行うこと無くコンパイルが可能になる」らしいので、とてもめでたいことなんだと思います。

参考：内部引数名と外部引数名について
https://wp-p.info/tpl_rep.php?cat=swift-biginner&fl=r20

『IBActionのsenderにはアクションが起きたUI要素のオブジェクトが入ります。
この場合は「タップ」というアクションが起きた「ボタン（UIButton）」がsenderに入ります。』だそうです。（丸々コピペすいません）

参考：senderというものについて
https://teratail.com/questions/116581

## 遷移先ページの設定をしよう
ボタンを押したら遷移させる。という機能にしたいのですが、そもそも「次のページ」がどのようなものか設定ができていません。

そのため、nextViewControllerというページをTopViewControllerでも使えるようにしてあげないといけません。

そこで下記のようなコードをTopViewController側に書きます。

```swift:TopViewController.swift
    let nextViewController = NextViewController()
```
意味がわかりませんね。
まず、letは「定数を代入する」力を持ちます。参考サイトを読むのが早いです。（雑）

参考：変数と定数について
https://wp-p.info/tpl_rep.php?cat=swift-biginner&fl=r10

ここで、まずnextViewControllerという変数の箱を作ります。
実はnextViewControllerという部分はなんでもいいです。箱にくっつける名前なだけなので。今回は「nextViewControllerを表示させる変数」なのでわかりやすいようにnextViewControllerにしたよ！って感じです。

その後の = でNextViewController()と書いています。

NextViewControllerの中身は、Cocoa Touch Classファイルを作成したままほっといていましたよね？これが書いてあるはずです。

```swift:NextViewController.swift
class NextViewController:UIViewController{
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}
```

要約すると「読み込みます」ってことです。よくわかりませんがこれでNextViewControllerのビューも読み込んでくれます。

## ボタンに遷移させる処理を加えよう
もう少しです。

TopViewControllerに次ページの情報を登録できましたので、あとは「ボタンを押したら」「次ページを読み込む」の指示を出したら大丈夫そうですよね。
ボタンの指示については下がわかりやすいのでそのままコードを拝借します。

```swift:TopViewController.swift
@objc func goNext(_ sender: UIButton) {// selectorで呼び出す場合Swift4からは「@objc」をつける。
        let nextvc = NextViewController()
        nextvc.view.backgroundColor = UIColor.blue
        self.present(nextvc, animated: true, completion: nil)
    }
```

参考：Swift： Storyboardを使わない画面遷移まとめ！
http://programming-beginner-memo.com/?p=825


今回は、letの処理も終わってますし、ボタンの色を青にする必要もないので、下の部分だけ貼り付けました。

```swift:TopViewController.swift
self.present(nextvc, animated: true, completion: nil)
```

 nextvc が nextViewController なのでそこを書き換えて、

```swift:TopViewController.swift
self.present(nextViewController, animated: true, completion: nil)
```

にすれば完成です！
TopViewControllerの中身をまとめるとこんな感じ

```swift:TopViewController.swift
import UIKit

class TopViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    let nextViewController = NextViewController()
    @IBAction func touchedButton(_ sender: UIButton) {
        self.present(nextViewController, animated: true, completion: nil)
    }
}
```

## storyboardを少しいじる
Xcode様にはstoryboardと呼ばれる機能があり、正直これを使えば上の処理が2分くらいでできるらしいです。私はどうして2分で終わるはずのことを4時間もかけてqiitaに書いているのでしょう。

Xcodeで新規プロジェクトを作成した際に、storyboardは「デフォルトで作成されるViewControllerという画面を最初に表示するよ！」と設定されています。
しかし、今回私はViewControllerは削除しており、最初にTopViewControllerが表示されてくれないと困るわけです。

storyboardの操作はビューの操作のときと似ています。
storyboardファイルを開いた後に、もともと登録されていたViewControllerをクリックします。そうするとビューのときと同じようにクラスを選択できる部分があるので、そこをTopViewControllerに変更します。

あともう一つ注意してほしいのが、**storyboard上に登録されているビュー**です。
私達はすでにビューは別に作っていますが、storyboard上にビューが乗っているとそちらが優先されてしまいます。
そのため、storyboardに乗っているViewを削除してください。私はこれを忘れていてずっとボタンが出てこなくて泣きました。


## 終わり
command + R でパソコン上に仮想iPhoneとアプリが立ち上がります！
ｳｺﾞｲﾀｱｱｱｱｱｱｱｱｱｱｱｱｱｱｱｱｱｱｱｱ
うれしいですね。

## 次回に向けての意気込み
書けば書くほど謎のスクール直伝秘伝のソースの比重があまりに多いことに驚きます。
みんなは小麦粉とオーブンでパン作ってるのに、私だけホットケーキミックスと炊飯器でパン作ってるみたいな気分。

今後は秘伝のソースマシマシでやるので、次回も進め方がおかしい様子を楽しんでくださいまし。