0
0

MVCについてコードを記載してアウトプットしてみた

Last updated at Posted at 2023-01-26

はじめに

MVCについてアウトプットしてみる。
また、アウトプットする上でNtificationCenterという通知方法を使用するが、本来の使い方ではない。そのため、あくまでMVCの学習の一環としてNtificationCenterを使用させていただきたい。

MVCの各々機能について

  • Model
    • システム内のビジネスロジックを担当する。
      • UIに関係しない処理全て
  • View
    • ユーザーが直接目にするView部分の描画処理を行う
  • Controller
    • ModelとViewの仲介役(橋渡し的役割)
    • ユーザーから入力された情報をModelに伝え、
    • Modelが受け取った情報をModelが更新したら、このControllerを介してViewへ描画を指示する

ソースコード

  • Model
Swift
import Foundation
import UIKit

//Model
//ビジネスロジック、UIに関係しない処理全て

//Modelがやること
//①データを表示する処理
//②テーブルセル押すと件数が増える処理
//※セルの個数を確定する処理(UITableViewのUITableViewDatasourceのcellForRowAt)はController(ViewとModelの仲介)で担当する責務ではないため、Modelで対応する


//ツイート自体のデータモデル
class TweetDataModel {
    let tweet: String
    
    init(tweet: String) {
        self.tweet = tweet
    }
}

class TweetListModel: NSObject, UITableViewDataSource {
    //Modelを監視するクラス
    let notificationCenter = NotificationCenter()
    
    //Modelで管理する配列に初期値を設定する
    var tweetList: [TweetDataModel] = [
        TweetDataModel.init(tweet: "Tweet: 0番目"),
        TweetDataModel.init(tweet: "Tweet: 1番目"),
        TweetDataModel.init(tweet: "Tweet: 2番目")
    ] {
        didSet{
            //Modelで管理している配列に変化があった場合に呼び出されて通知する
            //userInfoはnotificarionCenterにpostした時に値を受け渡すことができる、今回はtweetListの値を受け渡す
            //通知でViewControllerに変更を知らせる(配列の内容が変更時)
            notificationCenter.post(name: .init("changeTweetList"), object: nil, userInfo: ["list": tweetList])
        }
    }
    
    //配列に新しいツイートを追加する
    func addTweetList() {
        let tweetText = "Tweet: \(self.tweetList.count)番目"
        self.tweetList.append(TweetDataModel.init(tweet: tweetText))
    }
    
    //MARK: UITableViewDatasource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.tweetList.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
        let tweetModel = self.tweetList[indexPath.row]
        cell.textLabel?.text = tweetModel.tweet
        return cell
    }
}
  • View
Swift
import UIKit

//View

//Viewがやること
//ユーザーが直接目にするView部分の描画処理を行う
//UIViewクラスを作成し、xibファイルと紐付ける(UIViewControllerでcibファイルを持たない)

class TweetListView: UIView {
    @IBOutlet weak var tableView: UITableView!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
//        initメソッドはinitメソッド内で定数や配列の初期化などを行うためにある
        loadNib()
    }
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        loadNib()
    }
    
    func loadNib() {
        let view = Bundle.main.loadNibNamed("TweetListView", owner: self, options: nil)?.first as! UIView
        view.frame = self.bounds
        self.addSubview(view)
    }
}
  • Controller
Swift
import UIKit

//Controller
//ViewControllerでTableViewのデリゲートメソッドを宣言している

//Controllerがやること
//①Viewでのユーザーアクションを検知して、Modelに処理を走らせる
//②Modelの値の変化を受けて、Viewへ反映させる

class TweetViewController: UIViewController {
    
    //ModelのTweetListModel
    var myModel: TweetListModel? {
        //セットされるたびにdidSetが動作する
        didSet {
            //ViewとModelとを結合し、Modelの監視を開始する
            registerModel()
        }
    }
    
    override func loadView() {
        super.loadView()
        self.view = TweetListView()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        myModel = TweetListModel()
        settingTableView()

    }
    
    func settingTableView() {
        let tweetListView = self.view as! TweetListView
        tweetListView.tableView.delegate = self
        tweetListView.tableView.dataSource = self.myModel
        
        //TableViewに表示するCellを登録する
        tweetListView.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
    }
    
    //viewとModel監視する関数
    func registerModel() {
        guard let model = myModel else { return }
        
        //Modelにある配列が変化したらnotificationcenterでModelから通知を受け取ってaddObserverのクロージャー以降の処理を実行させる(今回でいう配列が変化したら、ここのviewにTweetListViewを作成し、TweetListViewのtableviewをリロードさせたい)
        model.notificationCenter.addObserver(forName: .init("changeTweetList"), object: nil, queue: nil) { [unowned self] notification in
            //Modelで更新した内容をViewへ反映(更新)
            let tweetListView = self.view as! TweetListView
            tweetListView.tableView.reloadData()
        }
    }
    
    @objc func onTapTableViewCell() {
        myModel?.addTweetList()
    }
}

//Viewでのユーザーアクションを検知して、Modelに処理を走らせる
extension TweetViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        //Modelでタップされたときに追加処理を行う(Modelに処理を走らせる)
        self.onTapTableViewCell()
    }
}

おわりに

間違い等ありましたらコメント欄にてご指摘いただけると幸いです。

参考記事

開発環境

  • Xcode-13.4.1
  • Swift version 5.7
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0