今更MVCとかでiOSアプリつくってみた（Swift）

# はじめに
20200411追記 
書き直したので[こっち](https://qiita.com/am10/items/1a877dc2939962a40aaf)を読んでほしい  
[これ](https://qiita.com/am10/items/407f82b8e7756e8082a8)のswift版です。
よくある色々な設計で実装してみたっていうやつです。
MVPとMVVMはMVCとあまり差がわからなかったのでMVCとVIPERで作ってみました。
どちらもおそらくこうだろうという感じで作っているので間違っていたらご指摘いただけたら幸いです。

# つくるもの

あまりに機能がなさすぎると色々な設計でつくっても違いがわかりにくいと思うので今回は下記のようなアプリを作ります。

## アプリ要件

[livedoor天気のWeb API](http://weather.livedoor.com/weather_hacks/webservice)(商用利用不可)を利用した各都道府県の天気を表示するアプリ。

対象はiOS10以降。

### 機能

４７都道府県を一覧表示し、選択した都道府県の今日、明日、明後日の３日間の天気を表示する

* 都道府県一覧の表示は各地方で絞り込みができる
* 都道府県のお気に入り登録ができる（端末で記憶する）
* 都道府県一覧の表示はお気に入りで絞り込みができる

### 画面構成

都道府県一覧画面と詳細画面の２画面。（絞り込みPop含め３画面）

#### 都道府県一覧画面

![default](https://user-images.githubusercontent.com/34936885/41820589-06b826d6-780f-11e8-841c-42a95b27b6a7.png)

* ４７都道府県を一覧表示
* 都道府県選択で通信で天気情報を取得し詳細画面に遷移する（エラー時は遷移しない）
* 星マークタップでお気に入り登録削除を行う
* お気に入りのみ表示チェックボックスのチェックでお気に入りのみ表示する
* 地方で絞り込みボタンで下の画像のようなポップを表示する

![default](https://user-images.githubusercontent.com/34936885/41820592-1559e7c4-780f-11e8-9409-bcab0515e897.png)

* チェックの切り替えで一覧表示を絞り込んで表示する

#### 詳細画面

![default](https://user-images.githubusercontent.com/34936885/41820596-22f70d80-780f-11e8-868f-5649566376dc.png)

* 選択した都道府県名を表示する
* 選択した都道府県の今日、明日、明後日の３日間の天気を表示する
* 表示内容は日付、アイコン、天気、最高気温、最低気温の５項目を表示する
* 右上の再読み込みボタンで天気情報を通信で再取得する

# 用語解説

MVCとかで個人で認識の違いが出るのはカタカナ語の意味があいまいなのも１つの原因かと思います。

MVCとか調べていてビジネスロジックって結局なんやねんとよくわからなくなるのでこの記事でいうカタカナ語の意味について書いておきます。（実際の意味とは違うかもしれませんが...）

## ビジネスロジックとは？

[ここ](https://wa3.i-3-i.info/word13666.html)の説明では「そのシステムにおける、システム固有の処理を行う部分」とある。

このアプリでいうと下記が該当

* 各地方での絞り込み
* お気に入りの登録
* お気に入りの絞り込み
* 天気情報の取得

## レイアウトとは？

このアプリでいうと下記が該当

* UIViewなどの部品の配置
* 都道府県一覧の表示
* 天気情報の表示

## ユーザアクションとは？

このアプリでいうと下記が該当

* ボタンのタップ
* セルのタップ

# それぞれの設計

つくったものは[ここ](https://github.com/adventam10/SwiftArchitecture)にあげました。

今回つくったものは通信に[Alamofire](https://github.com/Alamofire/Alamofire)、プログレス表示に[SVProgressHUD](https://github.com/SVProgressHUD/SVProgressHUD)、JSONデータを扱うクラスの作成に[JSONExport](https://github.com/Ahmed-Ali/JSONExport)を利用しました。
それぞれの設計の私の認識、ファイル数、ViewControllerの行数、つくった感想を書いていきます。

## ほぼViewController

とりあえず何も考えずにほぼViewControllerでつくったのが[これ](https://github.com/adventam10/SwiftArchitecture/tree/master)

### ファイル数

* .swiftファイル: 18 
* xibファイル: 5
* storyboard: 1

### ViewControllerの行数(コメント含む)

* 都道府県一覧画面: 217行
* 絞込みPop画面: 123行
* 詳細画面: 209行

### つくった感想

ファイル数は少なく開発スピードは早い。どのクラスも200行くらいでおさまっているのでこのくらいの規模ならこれもありかなと思います。

## MVC

プロジェクトは[これ](https://github.com/adventam10/SwiftArchitecture/tree/MVC)

### 認識

![mvc](https://user-images.githubusercontent.com/34936885/50717401-79897300-10ca-11e9-851f-584924ca64dd.png)

#### Model(該当するもの：class, struct)

* データの保持
* ビジネスロジック
* データ変更をControllerへ通知

#### View(該当するもの：UIView, UIViewController, xib, storyboard)

* 画面のレイアウト
* ユーザアクションをControllerへ通知

#### Controller(該当するもの：UIViewController)

* ModelとViewの仲介
* Viewからユーザアクションの通知を受けModelのデータを更新
* Modelからデータの更新通知を受けViewの表示を更新

### ファイル数

* .swiftファイル: 26 
* xibファイル: 6
* storyboard: 1

### ViewControllerの行数(コメント含む)

* 都道府県一覧画面: 159行
* 絞込みPop画面: 79行
* 詳細画面: 67行

### つくった感想

これはわりとそれっぽくつくれたんじゃないかなと思います。
ファイル数は少し増えますが、ViewControllerがかなり軽くなりました。ボタン押下時の処理などViewからControllerに通知しないといけなかったりと多少めんどくさいですが、1つ1つのクラスが軽量なので改修はしやすいんじゃないかなと思います。
このくらいの規模のアプリだとこの作りがいいような気がします。

### MVC(修正版2019/09/29)

前のMVCのやつを修正しました。
modelの役割にcontrollerへの通知とか書いときながらしてなかったり、Viewに条件分岐とか入ってたのでそこのあたり修正しました。

修正点

* modelからcontrollerへはdelegateで通知
* viewはもらった値を表示するだけ
* main.storyboard削除（ほぼ使ってなかった）
* 単体テスト追加

プロジェクトは[これ](https://github.com/adventam10/SwiftArchitecture/tree/MVC_V2)

#### ファイル数

* .swiftファイル: 28
* xibファイル: 6

#### ViewControllerの行数(コメント含む)

* 都道府県一覧画面: 174行
* 絞込みPop画面: 94行
* 詳細画面: 87行

## VIPER

プロジェクトは[これ](https://github.com/adventam10/SwiftArchitecture/tree/VIPER)

基本的には[この記事](https://qiita.com/hicka04/items/09534b5daffec33b2bec)を参考にしました。

### 認識

![viper](https://user-images.githubusercontent.com/34936885/50717418-8ad27f80-10ca-11e9-9e2c-eab4254b6f1c.png)

#### View(該当するもの：UIView, UIViewController, xib, storyboard)

* 画面のレイアウト
* ユーザアクションをPresenterへ通知

#### Interactor(該当するもの：class)

* ビジネスロジック（データ系）
* データ取得をPresenterへ通知

#### Presenter(該当するもの：class)

* データの保持
* ビジネスロジック（画面更新系）
* Interactorにデータの取得など依頼
* Interactorからデータの取得通知を受けViewの表示を更新
* Routerに画面遷移の依頼

#### Entity(該当するもの：struct)

* データの表現

#### Router(該当するもの：class)

* 画面遷移

### ファイル数

* .swiftファイル: 32 
* xibファイル: 6
* storyboard: 1

### ViewControllerの行数(コメント含む)

* 都道府県一覧画面: 118行
* 絞込みPop画面: 75行
* 詳細画面: 80行

### つくった感想

swiftのプロジェクトはVIPERで作るのが主流？な気がしたので挑戦してみましたがいまいちどこに何を書けばいいのかわかりませんでした。tableViewのデータリストとかはどこが持つべきか？Viewで表示する文字列の加工とか（気温に℃つけたりとか）はInteractorでやるべきか？など迷う部分が多々ありましたが、やっていけばなれそうな気もします。まだ不慣れなので役割分担がきっちりしていない部分もありますが、役割分担がきっちり決まれば割とみやすい感じがします。細かい部分は開発チームで明確化しておけばチームでやるならやりやすいような気がします。この規模のアプリだとめんどくさい気もしますが、今後の改修などを考えれば十分ありだと思います。

## MVVM (2019/04/29追記)

プロジェクトは[これ](https://github.com/adventam10/SwiftArchitecture/tree/Reactive)

### 認識

![mvvm1](https://user-images.githubusercontent.com/34936885/56886471-0dcc7b00-6aaa-11e9-82b2-601f3b8ab3e1.png)

#### Model(該当するもの：struct)

* データ表現
* データ変更をViewModelへ通知

#### View(該当するもの：UIView, UIViewController, xib, storyboard)

* 画面のレイアウト
* ユーザアクションをViewModelへ通知

#### ViewModel(該当するもの：class, struct)

* ビジネスロジック
* ModelとViewの仲介
* Viewからユーザアクションの通知を受けModelのデータを更新
* Modelからデータの更新通知を受けViewの表示を更新

### ファイル数

* .swiftファイル: 28 
* xibファイル: 7
* storyboard: 1

### ViewControllerの行数(コメント含む)

* 都道府県一覧画面: 164行
* 絞込みPop画面: 75行
* 詳細画面: 103行

### つくった感想

Modelからの通知はReactiveSwiftを利用したデータバインディングで行うのでModelの役割はデータ表現のみで処理は書かない。詳細画面の天気表示用にviewModelを追加してそこで表示データをゴニョゴニョするのでViewももらったデータをそのまま表示するだけになりいい感じになったような気がします。Reactive~は使い方が合ってるかわかりませんがviewControllerの処理がviewDidload部分にほぼ納まるのでスッキリする気がします。VIPERほどクラスを分けないのでいい感じがしますが、Reactive~を使い過ぎるとコードの難読化に繋がるのでなかなか難しい...

## おまけ (2019/04/29追記)

ライブラリ管理なども含めiOSプロジェクト構成に関して模索用に作りました。
アーキテクチャはReactiveSwiftを用いたMVVMっぽいので作りました。
[DIKit](https://github.com/ishkawa/DIKit)を使ってDIっぽいのを実装
詳しくは下記レポジトリのREADMEをみて下さい。

プロジェクトは[これ](https://github.com/adventam10/SwiftArchitecture/tree/Better)

### ViewControllerの行数(コメント含む)

* 都道府県一覧画面: 172行
* 絞込みPop画面: 85行
* 詳細画面: 111行

### つくった感想

ライブラリ管理などを含めどういう構成がいいのか模索してみました。基本的には[iOSアプリを作るときのおすすめ構成
2017年末版](https://medium.com/swift-column/ios-2017-4f04d00a5804)を参考にしています。画面はxibかstoryboardか迷いましたがstoryboardは色々書けて自由度が高い気がしたのでxibにしました。まだまだ模索中ですがとりあえず[R.swift](https://github.com/mac-cain13/R.swift)と[LicensePlist](https://github.com/mono0926/LicensePlist)は入れた方がいい気がしました.

# さいごに

この記事はだれかに意見して欲しいと思って書いたので何かちょっとしたことでも意見をくださるとありがたいです。
俺が思う「最強の設計はこれだ！」というのがあれば、是非上記の仕様でアプリつくってみて下さい。

# 参考

* [iOSアプリ設計大全集 2016](https://qiita.com/tattn/items/d4b95af0b60c3849243a)
* [これが最強のMVC(iOS)](https://qiita.com/koitaro/items/b3a924245fd72f22871a)
* [iOSをMVC,MVP,MVVM,Clean Architectureで実装してみた](http://rock-name.com/ios/ios-architecture)
* [VIPERアーキテクチャ まとめ](https://qiita.com/hicka04/items/09534b5daffec33b2bec)