【学習備忘録】(Swift)NotificationCenterを使ったCocoaMVCモデル

10693 ワード

はじめに

今までMVCパターンを聞いたことがあり、なんとなく実装していました。しかし、通知(Notify)の意味がわからな買ったので、実際に手を動かして理解していこうと思います。

MVCモデルとは

Appleのドキュメントアーカイブより、MVCデザインパターンについての説明です。

Model-View-Controller(MVC)デザインパターンは、アプリケーション内のオブジェクトに、モデル、ビュー、またはコントローラーの3つの役割のいずれかを割り当てます。このパターンは、アプリケーションでオブジェクトが果たす役割を定義するだけでなく、オブジェクトが相互に通信する方法を定義します。3つのタイプのオブジェクトはそれぞれ、抽象的な境界によって他のオブジェクトから分離され、それらの境界を越えて他のタイプのオブジェクトと通信します。アプリケーション内の特定のMVCタイプのオブジェクトのコレクションは、レイヤーと呼ばれることもあります(たとえば、モデルレイヤー)。

MVCは、Cocoaアプリケーションの優れた設計の中心です。このパターンを採用することの利点はたくさんあります。これらのアプリケーションの多くのオブジェクトは再利用可能である傾向があり、それらのインターフェースはより適切に定義される傾向があります。MVC設計のアプリケーションは、他のアプリケーションよりも簡単に拡張できます。さらに、多くのCocoaテクノロジーとアーキテクチャはMVCに基づいており、カスタムオブジェクトがMVCの役割の1つを果たす必要があります。

出典:https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html

サンプルコード

完成アプリ



ボタンを押すとテキストメッセージが変わるアプリです。

Model

可読性を上げるため,Notification.Nameをextentionで拡張しています。

extension Notification.Name {
    static let textModelDidChangeText
    = Notification.Name("ChangeTextModel.didChangeText")
}

notify()メソッドで通知を送信しています。

class TextModel {
    private(set) var text = "ボタンを押してください"

    func changeText() {
        text = "ありがとう"
        notify()
    }

    private func notify() {
        NotificationCenter.default.post(
            name: .textModelDidChangeText,
            object: nil
        )
    }
}

ViewController

通知を受信し,updateLabel()メソッドでtextを更新します。

class ViewController: UIViewController {
    @IBOutlet private weak var label: UILabel!

    private let textModel = TextModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupLabel()
        NotificationCenter.default.addObserver(
            forName: .textModelDidChangeText,
            object: nil,
            queue: OperationQueue.main,
            using: { [weak self] _ in
                self?.updateLabel()
            }
        )
    }

    @IBAction private func pressedButton(_ sender: Any) {
        textModel.changeText()
    }

    private func setupLabel() {
        label.text = textModel.text
    }

    private func updateLabel() {
        label.text = textModel.text
    }
}

GitHub

上記のサンプルコードを格納しています。