Swift PlaygroundsでのMVP実装を考えた
MVP実装考えなきゃいけないほど大規模開発しないよね
FatViewControllerガーって言うほど、iPad単体で大規模なプログラムは書かないとは思うのですが…
- 組み込みデバイスと通信するプログラムが多いので、ViewControllerが組み込みデバイスとの通信APIとごちゃごちゃになるのは必至
- 別のViewアーキテクチャの機器に移植するのが大変になる
- API変更があった場合の変更が辛くなる
MVCから逃げたいのはこのくらいかな。MVPにしたのはその他のアーキテクチャにくらべて学習コストが低そうと言うだけです。
MVPについてちょっとお勉強した
参考にしたサイト
そのまま、Model - View - Presenterで成り立っており、比較的それぞれが疎結合になっているアーキテクチャ
Presenterの役割が重要で、
- Viewからイベントを受け取り、Modelに処理を移譲
- Modelから結果を受け取り、Viewに通知
したがってModel、Viewとも、互いに独立している。
今回はModelはNotificationCenterを使い、Presenter通知しています。
iPad SwiftPlaygroundsですので、複数ファイルに記述するのが少々ハードルが高いので1ファイルに汚く書いてしまいました。
import PlaygroundSupport import UIKit import Foundation // MVPの練習 // protocol宣言 -------------------- protocol MyViewProtocol: class { func reloadData() } protocol MyModelProtocol: MyModelProtocolNotify { func fetchControl() } protocol MyModelProtocolNotify: class { func addObserver(_ observer: Any, selector: Selector) func removeObserver(_ observer: Any) } protocol MyViewPresenterProtocol: class { } // protocol宣言おわり--------------- class MyLiveView: UIView { } // ------------------------------- // View class MyViewController: UIViewController { private var myTextView = UITextView(frame: CGRect(x: 20, y: 20, width: 220, height: 60)) var presenter: MyViewPresenter! override func viewDidLoad() { super.viewDidLoad() view.addSubview(myTextView) presenter = MyViewPresenter(view: self) updateControl() } override func loadView() { super.loadView() view = MyLiveView() } @objc func updateControl(){ // Presenterに取得処理を移譲 presenter.updateModelControl() } } extension MyViewController: MyViewProtocol { // Presenterから呼ばれる処理 func reloadData() { myTextView.text = "通知を受信" } } // ------------------------ // Presenter class MyViewPresenter: MyViewPresenterProtocol { var view: MyViewProtocol var model: MyModelProtocol init(view: MyViewProtocol) { self.view = view self.model = MyModel() // NotificationCenter model.addObserver(self, selector:#selector(self.updated)) } // Modelに処理を移譲 func updateModelControl(){ model.fetchControl() } // Modelから更新の通知があったらViewに更新を依頼 @objc func updated() { //print("updated!!!") view.reloadData() } } // -------------------- // Model class MyModel: MyModelProtocol { func fetchControl(){ // NotificationCenterでPresenterに通知 self.notify() } } extension MyModel: MyModelProtocolNotify { var notificationName: Notification.Name { return Notification.Name(rawValue: "MyModel") } func removeObserver(_ observer: Any) { NotificationCenter.default.removeObserver(observer) } func notify() { NotificationCenter.default.post(name: notificationName, object:nil) } func addObserver(_ obserber: Any, selector: Selector) { NotificationCenter.default.addObserver(obserber, selector: selector, name: notificationName, object: nil) } } PlaygroundPage.current.liveView = MyViewController()