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

# はじめに

よくある色々な設計で実装してみたっていうやつです。（随時更新）

最近はMVCでつくるよう意識してみたのですが、MVCにしても個人で認識が違い個性がでてしまって共通の設計にはならないしそもそもMVCでいいのか？ということで私が思うそれぞれの設計（MVC,MVP,MVVM）について文書化しようとこの記事を書きました。（VIPERとCleanアーキテクチャもやろうと思ったのですがこの２つはちょっと意味がわからなかったので鋭意作成中です）

もともと設計とかは意識せずに実装してたのでMVCとかもあんまわかっていません。色々記事を読んでみましたがわかった気になるだけであんま理解していません。なのでこの記事で書いていることは間違っているかもしれません。


間違っていればどなたか「間違ってるよ」と優しくご指摘いただければ幸いです。

# つくるもの

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

## アプリ要件

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

対象はiOS10以降のiPhoneで縦画面固定。

### 機能

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

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

### 画面構成

都道府県一覧画面と詳細画面の２画面。（絞り込み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/TestApplicationArchitecture)にあげました。

今回つくったものはプログレス表示に[SVProgressHUD](https://github.com/SVProgressHUD/SVProgressHUD)、JSONデータを扱うクラスの作成に[JSONExport](https://github.com/Ahmed-Ali/JSONExport)を利用しました。(データの扱いはNSDictionaryでもいいと思うのですが、あるプロジェクトで同じキーなのに文字列や数値など型の違うものが入っているということがあり個人的にNSDictionaryに嫌悪感があるのでできるだけ使わないようにしました)

それぞれの設計の私の認識、ファイル数、ViewControllerの行数、つくった感想を書いていきます。

## ほぼViewController

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

### ファイル数

* .mファイル: 11 
* xibファイル: 6
* storyboard: 1

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

* 都道府県一覧画面: 570行
* 絞込みPop画面: 277行
* 詳細画面: 441行

### つくった感想

ファイル数は少なく開発スピードは早いですが、すでに１画面で570行なのでちょっと機能追加とかがあるとすぐに1000行超えのViewControllerが出来上がりそうな予感があります。保守とかを考えずに開発スピードだけ求められるならこれもありかもしれません。

## MVC

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

### 認識

![mvc](https://user-images.githubusercontent.com/34936885/42045308-30190142-7b36-11e8-8c1b-45e6bb182a6a.png)

#### Model(該当するもの：NSObject)
* データの保持
* ビジネスロジック
* データ変更をControllerへ通知

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

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

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

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

### ファイル数

* .mファイル: 31 
* xibファイル: 7
* storyboard: 1

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

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

### つくった感想

これはわりとそれっぽくつくれたんじゃないかなと思います。
ファイル数は大幅に増えましたが、役割が分かれているので多少機能追加があってもViewControllerが1000行いくことはないかと思いますが、modelが太りそうな気もします。ViewControllerが若干Viewの役割（navigationbarの表示とか）も担っているのでちょっとモヤっとします。
このくらいの規模のアプリだとこの作りがいいような気がします。

## MVP

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

### 認識

![mvp](https://user-images.githubusercontent.com/34936885/42045371-5866c418-7b36-11e8-8db0-ef1c991b4013.png)

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

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

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

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

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

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

### ファイル数

* .mファイル: 36 
* xibファイル: 7
* storyboard: 1

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

* 都道府県一覧画面: 280行
* 絞込みPop画面: 161行
* 詳細画面: 142行

### つくった感想

これは正直Presenterがこれでいいのかは疑問です・・・（なんか個人的にviewControllerと互いに参照し合うのが気持ち悪いです）
ViewControllerがViewに含まれるので役割の分担はMVCよりもキッチリできたような気がします。
画面遷移時に値を渡すときにどうやればいいのか苦戦しました。
役割が分かれているので機能追加とかのときに楽かと思いました。チームでやってる場合もgitにあげるとき競合が起きにくいのかなと思います。

## MVVM

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

### 認識

![mvvm](https://user-images.githubusercontent.com/34936885/42045396-68d81fa4-7b36-11e8-8357-4ab571bbed3d.png)

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

* データの保持
* データ変更をViewModelへ通知

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

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

#### ViewModel(該当するもの：NSObject)

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

### ファイル数

* .mファイル: 36 
* xibファイル: 7
* storyboard: 1

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

* 都道府県一覧画面: 280行
* 絞込みPop画面: 161行
* 詳細画面: 142行

### つくった感想

これはMVPとの違いがあまりわからないのですが、私の中ではModelが完全にデータの保持しかしないという認識です。
Modelの役割が大分スッキリしましたが、ViewModelがどんどん太っていくんじゃないかと思います（私の認識が間違ってるかもしれませんが・・・）。

## おまけ

ちょっと趣旨が違うかもしれませんが、MVCでつくったやつの汎用的な処理をカテゴリに分け、通信処理を別クラスにまとめたものをつくってみました。
つくったやつは[これ](https://github.com/adventam10/TestApplicationArchitecture/tree/MVC_Plus)

### 認識

私の中でMVCのやつがしっくりきたので汎用的な処理をまとめてもうちょっとスッキリしたつくりにしてみました。通信処理もAPIとかパラメータは通信ごとに変わるかもしれませんが通信先サーバは大抵変わらないかなと思い通信処理もまとめてみました。通信処理クラスは全ControllerのModelに当たるのかなと思います。

### ファイル数

* .mファイル: 37 
* xibファイル: 7
* storyboard: 1

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

* 都道府県一覧画面: 257行
* 絞込みPop画面: 141行
* 詳細画面: 90行

### つくった感想

普段のつくりにこれが一番近いのでしっくりきました。
機能が増えるとControllerとModelが1000行超えることが割とあるので場合によっては他の設計も考慮するべきなのかなと思います。

# さいごに

この記事はだれかに意見して欲しいと思って書いたので何かちょっとしたことでも意見をくださるとありがたいです。（何か現場の人と話合っていても同じ方向に意見が偏っていっている気がして外の人の意見が聞きたいです。）

俺が思う「最強の設計はこれだ！」というのがあれば、是非上記の仕様でアプリつくってみて下さい。

私はほぼObjective-Cしか使ったことがないペーペーのプログラマーなので記事内容やgithubのコードにおかしなところがあればご指摘いただければ幸いです。

# 参考

* [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)