【iOS・設計】MVCアーキテクチャ【サンプルコード付き】

公開日: 

はじめに

今回は、iOS アプリ開発においてとても大切な設計の中の、MVC アーキテクチャというものについて解説していきます。

アーキテクチャって何?

ていうかたはよかったら下の記事を読んでみてください。

https://www.yukendev.com/blogs/book-ios-architecture

MVC アーキテクチャとは

MVC アーキテクチャは

関心を UI の描画処理(View)とそれ以外のロジック(Model)に分ける

という考えをもとにした GUI アーキテクチャの一つで、GUI アーキテクチャの元祖とも言えるアーキテクチャです。そして、その考えを iOS アプリに持ち込んだのものをCocoa MVCと言います。なので、この記事で解説するのは正確にいうとCocoa MVCになります。以下、『Cocoa MVC』を『MVC』と表記することにします。

MVC では、

  • 入力 -> Controller
  • 出力 -> View
  • データの処理 -> Model

という風に定義します。これらの頭文字を取って**MVC(Model-View-Controller)**と呼ばれているわけです。MVC の考え方を簡潔にまとめると下の図のようになります。

MVC の大きな特徴であるのが、ModelView が独立しているということ。ViewModel の間に Controller が入り、ControllerViewModel を保持することでこれを実現しています。

これにより、ViewModel の再利用性が高くなるのが大きなメリットです。しかし、ControllerViewModel を保持するため、Controller クラスが肥大化しがちなのが問題点(Fat View Controller)になりがちです。まとめると、

  • Model: 各種ビジネスロジックのかたまり
  • View: 画面の描画を担当
  • Controller: Model オブジェクトと View オブジェクトを保持し、お互いの架け橋になる

メリット: View と Model の再利用性が高くなる

Controller クラスが肥大化しがち

MVC の概要は以上です。

サンプルアプリ

以上の MVC の考え方を踏まえて、数をラベルに表示し、プラス・マイナスボタンで数を+1, -1 し、5 の倍数の時にはラベルの色を赤くするという簡単なサンプルアプリを作ってみました。

ソースコード

https://github.com/yukendev/sampleMVC

Controller.swift
import UIKit

// MARK: -- Controller
class ViewController: UIViewController {

    // ControllerがViewを保持
    @IBOutlet weak var countLabel: UILabel!

    // ControllerがModelを保持
    var model: Model? {
        didSet { registerModel() }
    }


    override func viewDidLoad() {
        super.viewDidLoad()

        model = Model()

    }

    private func registerModel() {
        guard let model = model else { return }

        // Modelの値をControllerが監視
        model.notificationCenter.addObserver(forName: .init(rawValue: "count"),
                                             object: nil,
                                             queue: nil) { notification in
            if let count = notification.userInfo?["count"] as? Int {
                // Viewの描画を更新
                self.countLabel.text = "\(count)"
                if count % 5 == 0 && count != 0 {
                    self.countLabel.textColor = .red
                } else {
                    self.countLabel.textColor = .black
                }
            }
        }
    }

    // View -> Controller -> Modelに処理を依頼
    @IBAction func minus(_ sender: Any) { model?.minus() }
    @IBAction func plus(_ sender: Any) { model?.plus() }
}
Model.swift
import Foundation

// MARK: -- Model
final class Model {

    private(set) var count: Int = 0 {
        didSet {
            notificationCenter.post(name: .init(rawValue: "count"), object: nil, userInfo: ["count": count])
        }
    }

    let notificationCenter: NotificationCenter = NotificationCenter()

    func plus() { count += 1 }

    func minus() { count -= 1 }
}

『View と Model が独立している』『Controller が View と Model の橋渡し役』ということを意識して作りました。このアプリでは、Modelcountという変数を保持し NotificationCenter を使用することで、ControllerModel の count を監視する状態を実装しています。また、今回は StoryBoard を用いて作ったので UILabel, UIButton のようなパーツ 1 つ 1 つが MVC の View に当たるのかなと思いました。とても簡単なアプリなので MVC の考えを理解しやすいのではないでしょうか。

最後に

今回はMVC アーキテクチャについて解説しました。しかし、アーキテクチャはあくまで考え方、概念であって、必ずしも正解があるわけではありません。実装したい機能や、チームの考え方によって内容は変わってくると思います。この記事はあくまでその 1 例として読んでいただけたら幸いです。また、間違いや、もっといい方法などがありましたら教えていただけるとありがたいです。

では、Bye