最近、デザインパターンが増えてきたので、まとめていこうかなと思います。
記念すべき第1回はMVCです!!
MVCを調べてたら、何種類か出てきて困りましたが、自分が理解できて使えそうな形のものを紹介していきたいと思います。
なので、自分の知ってるのと違うという場合もありますが、コメントなどで教えてもらえたら勉強になりますのでぜひお願いします(笑)
今回の実装コードは、Swiftが個人的に好きなのでSwiftをつかいます
MVC構成要素の概要
Model
データの保持
データの管理
ビジネスロジック
View
modelの情報を表示する
Controller
ユーザーからの入力を受け取る
modelへ入力を伝える
iOSではViewControllerというクラスがController
の役割をします
今回は、ViewControllerクラスにView
も持たせました
MVC構成要素の実装
Model
MVCModel.swift
import Foundation
// データの変更を通知するためにdelegateを実装
protocol MVCModelDelegate {
func didChange()
}
class MVCModel {
public var count = 0;
var delegate: MVCModelDelegate? = nil
// ④データの変更用メソッドを定義
func inc() {
count += 1
delegate?.didChange()
}
func dec() {
count -= 1
delegate?.didChange()
}
}
ViewController
MVCViewController.swift
import Foundation
import UIKit
class MVCViewController: UIViewController, MVCModelDelegate {
/** Controller側の実装 **/
let mvcModel = MVCModel()
override func viewDidLoad() {
super.viewDidLoad()
// 初期値を表示するためにview側の表示更新を呼ぶ
didChange()
mvcModel.delegate = self
}
// ②ユーザーからの入力イベント
@IBAction func inc(_ sender: Any) {
// ③Modelのメソッドを呼ぶ
mvcModel.inc()
}
@IBAction func dec(_ sender: Any) {
mvcModel.dec()
}
/** View側の実装 **/
@IBOutlet weak var countLabel: UILabel!
// ⑤Modelからのdelegate
func didChange() {
countLabel.text = String(mvcModel.count)
}
}
制御フロー
- ユーザーが入力をする(incボタンをタップ)
-
Controller
が入力を受け取る - 入力に対応した
Model
のメソッドを呼ぶ -
Model
のデータが変更された場合は、delegateが呼ばれる -
View
で表示を更新する
画面遷移
画面遷移がある場合の実装
- 遷移元(
MVCViewController.swift
) - 遷移先(
MVCSubViewController.swift
)
ViewController
MVCViewController.swift
extension MVCViewController {
// ②ユーザーからの入力イベント
@IBAction func display(_ sender: Any) {
// SubViewController画面に遷移
performSegue(withIdentifier: "presentMVCSubViewController", sender: self)
}
// ③画面遷移の際呼ばれる
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// ④遷移先のViewControllerにModelクラスを渡す
if let destination = segue.destination as? MVCSubViewController {
destination.mvcModel = mvcModel
}
}
}
SubViewController
MVCSubViewController.swift
import Foundation
import UIKit
class MVCSubViewController: UIViewController {
var mvcModel: MVCModel? = nil
@IBOutlet weak var countLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// ⑤初期値を表示
if let count = mvcModel?.count {
countLabel.text = String(count)
}
}
}
制御フロー
- ユーザーが入力をする(画面遷移ボタンをタップ)
-
Controller(MVCViewController)
が入力を受け取る -
Controller(MVCSubViewController)
画面に遷移する -
Model
クラスの参照をMVCSubViewControllerクラスに渡す -
View(MVCSubViewController)
で渡されたModel
のデータを表示する
まとめ
作ってみた感想になってしまいますが、メリットとデメリット
メリット
- 制御フローが
User → Controller → Model → View
とわかりやすくなっている - 「わかりやすい = 作りやすい」と思う
-
Model
だけを渡すので、ViewController間でのデータの受け渡しが簡単
デメリット
-
View
とController
が含まれるのでViewControllerクラスが肥大化する -
Model
もデータの種類ごとにうまく分けないと肥大化する -
Model
が複数個できたときに、どのController
で参照されているのかを追うのが大変
追記
2017.11.16
投稿後にGistとの連携ができず、止むを得ず同じ内容の投稿をさせていただきました
https://qiita.com/hmhmsh/items/271a6cb309761bd965d3