iOS
Swift

MVCモデルについての私の解釈

はじめに

年末年始にiOSアプリ開発の勉強をしていて,
MVCモデルについて自分なりの理解ができたので,まとめてみました.

MVCモデルとは

よく見る定義

アプリケーション作成時に用いる設計パターンの1種で,
ソースコードをModel, View, Controllerの3つの役割に分割して開発する手法.

  • Model : システムの中でビジネスロジックを担当する
  • View : 表示や入出力といった処理をする
  • Controller : ユーザーの入力に基づき,ModelとViewを制御する

Viewがアプリの見た目の部分を制御するってのはわかる.
ControllerとModelってなんかわかりにくい.
ビジネスロジックってなんですか...というのが僕の初見の感想です.

勉強してみてしっくりきた例え

難しい概念も,身近なものにうまく例えることで理解できることありますよね.
MVCモデルの理解をするにあたり,しっくりきた例えはレストランです.

MVCモデルの相互作用はレストランでの流れに似ています.

  1. まず客はウェイターに対して料理を注文します.
  2. ウェイターは注文があったことをキッチンに伝えます.
  3. キッチンではシェフが冷蔵庫などから素材を取り出し,
  4. 注文通りの料理を作ります.
  5. 完成した料理をウェイターがテーブルに運びます.
  6. 料理が客の元へと届けられます.

この時,それぞれをこう置き換えてみます.

  • レストラン : アプリケーション
  • 客 : ユーザー
  • テーブル : View
  • ウェイター : Controller
  • キッチン : Model
  1. まずUser(客)はController(ウェイター)に対してイベント通知(料理を注文)します.
  2. Controller(ウェイター)は注文があったことをModel(キッチン)に伝えます.
  3. Model(キッチン)ではシェフがDataBase(冷蔵庫など)から素材(data)を取り出し,
  4. モデルで定義されている形に整形します(注文通りの料理を作ります).
  5. 完成した料理をController(ウェイター)がView(テーブル)に運びます.
  6. 料理が客の元へと届けられます.

スクリーンショット 2019-01-11 17.58.43.png

僕の中でかなりしっくりきました.
この例えから
・Viewはユーザに対する表示や入出力部分を扱う役割.
・ModelはDataBaseからデータを取ってきて定義されている形(モデル)に変える役割.
・ControllerはModelとViewの仲介であり,Modelから受け取ったデータをViewに表示させたり,Viewから受け取った入力をModelに伝える役割.

という風に解釈できました.

MVCモデルに基づいたアプリ制作

制作したもの

Swiftを用いたQuizアプリケーション.

スクリーンショット 2019-01-11 17.02.46.png

プロジェクトの構造

スクリーンショット 2019-01-11 17.40.43.png

View

swiftを使ったiOSアプリなのでViewはstoryboardを使って作成.

スクリーンショット 2019-01-11 17.56.44.png

Model

本アプリケーションで使用する問題を格納するクラス.

Question.swift
import Foundation

class Question {
    let questionText: String
    let answer: Bool

    init(text: String, correctAnswer: Bool) {
        questionText = text
        answer = correctAnswer
    }
}

また,今回はデータベースとのリモートにやりとりすることはせず,
Question.classのリストを持つQuestionBankを作成.

QuestionBank.swift
import Foundation

class QuestionBank {

    var list = [Question]()

    init() {
        let newQuestion = Question(text: "日本の首都は東京である.", correctAnswer: true)
        list.append(newQuestion)

        list.append(Question(text: "A slug\'s blood is green.", correctAnswer: true))
    }
}

Controller

ここでは,Modelで作られたデータをViewに反映させたり,
Buttonが押されるなどのアクションを検知して処理をするという部分を実装している.

ViewController.swift
import UIKit

class ViewController: UIViewController {

    //Place your instance variables here
    let allQuestion = QuestionBank()
    var pickedAnswer: Bool = false
    var nowQuestionIndex: Int = 0
    var score:Int = 0

    @IBOutlet weak var questionLabel: UILabel!
    @IBOutlet weak var scoreLabel: UILabel!
    @IBOutlet var progressBar: UIView!
    @IBOutlet weak var progressLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        nextQuestion()
    }


    @IBAction func answerPressed(_ sender: AnyObject) {
        if sender.tag == 1 {
            pickedAnswer = true
        }
        else if sender.tag == 2 {
            pickedAnswer = false
        }

        checkAnswer()

        nowQuestionIndex += 1

        nextQuestion()
    }


    func updateUI() {
        scoreLabel.text = "score: \(score)"
        progressLabel.text = "\(nowQuestionIndex + 1) / 14"
        progressBar.frame.size.width = (view.frame.size.width / 14) * CGFloat(nowQuestionIndex + 1)
    }


    func nextQuestion() {

        if nowQuestionIndex <= 13 {
            questionLabel.text = allQuestion.list[nowQuestionIndex].questionText

            updateUI()
        }
        else {
            let alert = UIAlertController(title: "Awesome", message: "You've finished all the question, do you want to restart question?", preferredStyle: .alert)

            let restartAction = UIAlertAction(title: "Restart", style: .default) { (UIAlertAction) in
                self.startOver()
            }
            alert.addAction(restartAction)

            self.present(alert, animated: true, completion: nil)
        }

    }


    func checkAnswer() {
        let correctAnser = allQuestion.list[nowQuestionIndex].answer

        if correctAnser == pickedAnswer {
            ProgressHUD.showSuccess("Corredt!")
            score += 1
        }else {
            ProgressHUD.showError("Wrong")
        }
    }


    func startOver() {
        nowQuestionIndex = 0
        score = 0
        nextQuestion()
    }



}

まとめ

今回伝えたかったことは,

MVCはレストランに例えるとわかりやすいんじゃないかなーということ

簡単なクイズアプリでMVCモデル開発を感じれましたーということ

最後に調べてて感じたことは,
MVCモデルにこれが絶対という正解はないんじゃねってことでした.