Help us understand the problem. What is going on with this article?

これが最強のMVC(iOS)

More than 3 years have passed since last update.

前に、MVCについての記事を書かせて頂いたのですが(おデブになりがちな、UIViewControllerをスッキリさせる魔法のルール)、色々調べ考えている内に「間違ってるぞ」ということに気づきました。

それを踏まえ、実際にUITableViewを使った実際に良くありそうなコードを具体例に上げご説明したいと思います。

そもそもMVCとは

MVCとは、有名なこのスライドに書かれている通りこれ「やはりお前らのMVCは間違っている」です。

やはりお前らのMVCは間違っている.png

しかしほとんどの世に出ているiosアプリのMVCの構造を見ると以下の図の様になっています。
(これはこのスライドの中で全力でdisられているMVCです)
やはりお前らのMVCは間違っている.png

そして私は、「なんだよ、みんなMVC間違ってんじゃん、ははーん」と思い前回の記事を書きました。
おデブになりがちな、UIViewControllerをスッキリさせる魔法のルール

この記事鵜呑みにした人ごめんなさい、完全に間違ってました。

なぜ間違ってたかと申し上げますと。
公式のマニュアルにこんな記述がございました。
要約すると、

「従来のMVCでも全く問題無いが理論上の問題があります」 ← どゆことやねん

https://developer.apple.com/jp/documentation/CocoaEncyclopedia.pdf
https___developer_apple_com_jp_documentation_CocoaEncyclopedia_pdf.png

さらにCocoaで使われているMVCがコレだとのこと
「完全にあのスライドでdisられてるパターンやーー」
https___developer_apple_com_jp_documentation_CocoaEncyclopedia_pdf.png

と紆余曲折があり、やはり従来のMVCは使うべきではないと結論づけました。

では改めまして

これが最強のMVCやーーー

いくぞおーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

まずはView編

1.必ずカスタムViewを作る

通常UIViewControllerのviewプロパティにUIViewのインスタンスが割り当てられます。それをカスタムUIViewに変えましょう。

たまにやり方を間違って以下の様に書く人がいるのですが、これでは間違いです。
まあ、動くには動きますが。

Controller.swift
override func viewDidLoad() {
    super.viewDidLoad()
    self.view.addSubview(CustomView())
}

カスタムViewを設定する場合は以下の様に書きましょう。

Controller.swift
override func loadView() {
  self.view = CustomView()
}

2.画面に表示させたい物は全てカスタムViewのイニシャライザでaddSubViewする(Viewのサイズ、位置調整はここではしない)

カスタムView.swift
 required init(model: QiitaViewModel) {
    table = UITableView(frame: CGRectMake(0, 0, 0, 0), style: UITableViewStyle.Plain);
    refreshControl = UIRefreshControl()
    table.addSubview(refreshControl)

    super.init(frame: CGRectMake(0, 0, 0, 0));
    self.addSubview(table);
}

3.Viewのサイズ、位置調整はlayoutSubviewsで行う。

これは、画面回転をさせた時に恩恵を感じます。

カスタムView.swift
override func layoutSubviews() {
    super.layoutSubviews()
    table.frame = self.frame        
}

4.カスタムViewの中にコントローラーから制御したいインスタンスがあるなら公開しちゃいましょう。

例えばTableViewのbackgroundColorの色を変えたい時に、カスタムViewに「tableColor」的なメソッドを作って、そこを介してTableの色を変えるということをやってる記事をちょくちょく見かけるのですが、それはちょっと違うと思います。

そうする理由は分かります、要するにカプセル化にこだわっているわけです。
でもなんの為のカプセル化を考えればもうちょっと違う判断ができるのではないかと思います。
これに関しては多くは書きません、話が飛躍するので。
ということで、Viewの中にコントローラーから制御したいインスタンスがあるなら公開しちゃいましょう。

それとMVC的に見た時に、ボタンタップ等のイベントはコントローラ側で受け取る必要があるので、公開しておかないと相当めんどいことになる

次にModel編

1.すべこべ言わずに一つのコントローラーに一つのModelを作りましょ。

こいつにロジックを突っ込むわけですね。

Controller.swift
class QitaListViewController: UIViewController,UITableViewDelegate {
    private let mModel = QiitaViewModel();

最後にController編

1.カスタムViewの中のViewを直接触る

上で説明した内容と少しかぶりますが、カスタムViewのsubViewのあたるViewをコントローラから直接触って制御しています。

Controller.swift
override func viewDidLoad() {
    super.viewDidLoad()
    let qiitaListView = self.view as! QiitaListView
    qiitaListView.refreshControl.addTarget(self, action: "tableUpdate:", forControlEvents: UIControlEvents.ValueChanged)
    qiitaListView.table.delegate   = self;
    qiitaListView.table.dataSource = mModel;
}

2.delegateはself,dataSourceはmodel

上のコードでは、tableのdategateにselfを突っ込んで、dataSourceには作ったmodelを突っ込んでいます。
これはどうしてかと申しますと、dataSourceに関しては、すべてdataSourceメソッド内だけで完結させる処理を書きますが、delegateに関しては、例えばセルがタップされたら別の画面へ遷移といったようなことをする必要があり、modelに書くのは得策ではないので、delegateはselfを突っ込みます。

細かいこところはソースみてー

全部説明するのは辛いので、ビルド実行できるものをアップしているので、細かい所はそこでご確認ください。
https://github.com/yamasakitomohiro/PerfectMVC

質問も、ご批判も、どんとこいです。

koitaro
ITエンジニアです。スマホアプリ、Webサービス開発幅広くやっております。 最近は、「人は何によって動かされるのか」に興味があり、コーチングなどを学んでおります。 スピーチも大好きです。
i-standard
五反田バレーを牽引するスタートアップ
http://www.i-standard.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした