質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.65%

mvcのmodelについて教えて下さい

受付中

回答 5

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,450

yoppy0066

score 293

swiftでiosアプリ開発の勉強中で、mvcのmodelについて調べているのですがちょっとわからなくなったので教えて下さい

まず、modelはシングルトンで実装する。ものなのでしょうか?

作りたいのは以下のようなものだとします
・メモの一覧画面(ListViewController)
・メモの詳細画面(DetailViewController)
※一覧画面の情報は外部のapiから取得するものとします

で、やりたかったこととしては詳細画面でデータの変更などを行った場合に一覧画面でも反映させるといったことで、シングルトンなmodelを作って以下のような実装になるのかなと考えました

で、疑問に思ったのがモデルをシングルトンにするとたとえば一覧にはいくつもカテゴリなどがあったとするといきなり破綻する気がしました、、、
こういう場合はモデルにそれぞれのカテゴリごとのlistを持つような実装にするのが一般的なのでしょうか?

モデル
ModelMemo: NSObject {
    var list: [Dictionary<String,AnyObject>]

    func getByApi() {
        // apiからデータを取得してlistにセット
    }

    func update() {
        // apiからデータを更新してlistに反映
    }
}

一覧画面
class ListViewController: UIViewController {
    var memos: ModelMemos

    override func viewDidLoad() {
        self.memos = ModelMemos・・・->getInstance()
        self.memos->getByApi()
    }
}

詳細画面
class DetailViewController: UIViewController {
    var memos: ModelMemos

    override func viewDidLoad() {
        self.memos = ModelMemos・・・->getInstance()
        var memo = self.memos->getByRow(行番号とか)
    }

    func updateMemo() {
        self.memos.update()
    }
}

mvcとかあんまりわかってないので全然ちがってたらすみませんが、どなたかご教授いただけないでしょうか


__moaiさんへ
実装したい機能のイメージとしては以下のようなものになります
1. セグメントコントロールに新着・人気がある
2. セグメントコントロールの下にリストがある(テーブルビューで実装)
3. リストの各セルにはブックマークボタンがあり、登録中・解除中で色が変わる
4. リストのセルをタップすると詳細画面へ遷移する
5. 詳細画面にもブックマークボタンがある

で、悩み出した原因としては詳細ページでブックマークして一覧に戻ったときにブックマークの状態をリストにも反映させなくてはいけないなというところから始まりました。
また、セグメントコントロールを切り替えた際にも同様の問題が起きえます

そして今検討中のコードが以下のようなものになります

class ModelDemo : NSObject {
    // 新着リスト・人気リスト
    dynamic var list: [Dictionary<String,AnyObject>] = [Dictionary<String,AnyObject>]()
    dynamic var list2: [Dictionary<String,AnyObject>] = [Dictionary<String,AnyObject>]()

    class var sharedInstance : ModelNotes {
        ・・・
    }

    // APIの処理など
}

// 一覧ページ
class ListViewController : UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        // リストデータの監視
        ModelDemo.sharedInstance.addObserver(self, forKeyPath: "list", options: .New, context: nil)
        // apiでのデータ取得
        ModelDemo.sharedInstance.getList()
    }

    // データの監視
    override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
        tableView.reloadData()
    }

    // ブックマーククリック
    func onclickBookmark(sender: UIButton) {
        // apiをたたいて更新
        ModelDemo.sharedInstance.update(・・・)
        // 画面更新のためにこちらも更新
        ModelDemo.sharedInstance.list[sender.tag]["isBookmark"] = true
    }
}

// 詳細画面
class DetailViewController: UIViewController {
    // 選択された行番号
    var row: Int!

    // ブックマーククリック
    func onclickBookmark(sender: UIButton) {
        // apiをたたいて更新
        ModelDemo.sharedInstance.update(・・・)
        // 画面更新のためにこちらも更新
        ModelDemo.sharedInstance.list[row] = true
    }
}












  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

0

MVCのModelはオブジェクトじゃなくて、コンポーネントです。
だから、シングルトン・オブジェクトという考え方はありません。
また、1クラス=1コンポーネントという対応もありません。

今回、カテゴリというものが必要なら、カテゴリを持つModelコンポーネントを作るだけです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/08/01 21:34

    いつもご回答頂きありがとうございます。

    いまいちイメージがつかないのですが、今回の例だとどのようなコードになるのが一般的なのでしょうか?

    キャンセル

  • 2015/08/01 21:41

    MVCのModelは、アプリケーション・モデルなので、どんな内容のアプリケーションなのかが分からないと、コードは書けません。

    ただ単に、カテゴリ分けされたメモがあるだけなら、
    protocol Memo {
    func postMemo(text:String, category:String)
    var allMemos:[(text:String, category:String)] {get}
    }
    こんな感じだと思います。
    ちなみに、正式にコンポーネントを作る場合は、インターフェースが必要です。

    キャンセル

0

何でモデルはシングルトンであるという考えに至ったのか謎ですが、
モデルは別にシングルトンである必要はありません。

MVCという言葉はいろんな人が色んな意味で使ってますが、
基本、MV○系のModelと言うのは、単に「UI実装の詳細を知らない部分」ぐらいの広い範囲です。
例えばメモなら
メモクラスや
メモをどこかに永続化するクラスとか
メモの生成・読み込み・更新・削除手順を提供するクラスとか
外部APIのラッパークラスとか
これら全部「Model」です

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/08/01 21:35

    ご回答頂きありがとうございます。

    いまいちイメージがつかないのですが、今回の例だとどのようなコードになるのが一般的なのでしょうか?

    キャンセル

0

回答者の方の意見が異なるように、MVCは結構意見が異なることが多いように思います。
その証拠に、MVC以外にもMVVMあったりMVPだったり、色々な考え方があります。

なので、MVCはなにを達成するためのものなのか、を自分なりに考えて答えを出すのがいいのだろうと最近では思うようになりました。

ちなみにこのスライドが一番しっくり来てなるほど、と思ったので共有しておきます。
http://www.slideshare.net/mokemokechicken/iosandroidmodel

そして上記のスライドを元に考えてみると、Cocoa Framework内でもCoreDataがスライドで語られているものに近いかな、と思います。


Modelは基本死なず、質問者さんが言うようにシングルトンで作ってもいいと思います。
そしてMVCでViewとくっつくのはモデルではなく、エンティティですね。CoreDataで言うと。

つまりモデルはいわゆるデータベースそのものに近く、内部のデータをエンティティとして扱います。
そしてそれらのデータをどう使うか、という部分をコンテキスト(NSManagedContext)が担う、という構成です。


今回の質問に当てはめてみると、データを保持しておくのがモデル。
一覧や詳細で使われる生のデータがエンティティ。
そして編集されたりして、データの更新などを管理するのがコンテキストでしょうか。

これ以降はどう設計するかと、どういうコンセプトで作るかによるので一概にこれがこうです、とはならないと思います。

あと質問内に「カテゴリ」と書かれていますが、ちょっとこれがなにを指すかが分かりませんでした。
データはあくまでデータでしかないので、それをカテゴライズしてどう表示するかは「データをどう扱いたいか」を自身で定義し、それを実装することになると思います。
(例えばデータにカテゴリの枠を設けて、カテゴリ単位で抽出し、それをリストとして表示する、とか)

上でも書いたようにデータはあくまでデータでしかなく、カテゴライズするのはコントローラだったり、の部分が担うことになると思います。


と、長々と書きましたが最初にも書いたように、表示とデータを分離しておくといいよね、というのがMVCの発端であり、それをどう理解して実装するかは実装者それぞれの判断になるかと思います。

とはいえどうすりゃいいんだ、ってのも分かるので、まずはCoreDataの実装を参考にしてみるのもいいかもしれません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

ごめんなさい、前回の回答で混乱させてしまいましたかね・・
MVCっていうのはプログラムの設計でいう概念的なお話なので、特に拘って悩むようなことでもないですよ

まず簡単に概念を実例を交えて説明をすると

View

アプリの表示している画面を作ってる部分、iOSだとUIViewがそうですね

Controller

ユーザーからの操作を受け取ってModelに伝える部分、UIViewControllerがそうですね

Model

ここで出てくるのがModelなんですが、基本的にViewでもControllerでもないコードを指します


例えば電卓アプリを作っていたとして、電卓のボタンだったり背景だったりをViewとするなら、ユーザーがボタンを押して画面に数字を出させるためのイベントを起こすのがController、電卓の+を押したときに計算される足し算のロジックとかの部分はModel

なので画面とは関係無いようなView/Controller以外のコードをModelと思って問題ないかなーと思います(なのでapiと通信する部分もModelですね)

そしてここからはModelって広い括りの中のお話になるのですけど、シングルトンっていうのは一旦忘れて、データをどうやって画面と画面の間で使い回すかってことを考えていきましょう

yoppy0066さんが扱いたいのはどんなデータですか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/08/02 02:47

    丁寧にご回答いただきありがとうございます。
    私の理解が足りなくてmvcとかとはまた別の話になってきている気もしてきました、、、

    内容が長くなったため質問欄に追記させていただきました

    キャンセル

0

ここで行っているModelは、
ブックマークの内容と、ブックマークの状態をまとめたクラス、ということですよね?

モデルデータを配列や辞書に格納してそこからデータを引き出すのであれば、
前回の質問の回答にあった、シングルトンで実装するのが一番自然でしょう。

モデルのデータ表現が複雑になるのであれば、そのデータ単体を表現するModelクラスを作成するのがよいかと。

モデルクラスには、現在のブックマークの内容と状態をget/setするメソッドを実装しておき、
ViewControllerのアクションでブックマークの状態が変化したらModelクラスのsetで状態を更新させる、
ViewControllerのビューが更新されるタイミングでModelクラスにブックマークの内容と状態を問い合わせる、
というのがただしいかと。

class ModelDemo : NSObject {
    
    // モデルを一意に識別できるような変数が必要。APIアクセスでリストにIDがついているならそれを入れる
    var api_id: Int
    var demoName: String
    var content: String
    var isNew: Bool
    var isPopular: Bool
    var bookmarked: Bool
    
    init(name:String, content:String, new: Bool, popular: Bool) {
      // 初期化コードは省略
    }
    // 以下、プロパティの更新メソッド等々
}
みたいなモデル一つ一つを表現するModelクラスを作成して、
そのModelを更新したり、新着などのフラグでリスト取得するような処理は、
モデル(って言っていいのかな?ヘルパー?)クラスを別途作るか、モデルクラスのクラスメソッドで対応し、
ViewControllerはそこからリストを取得するようにすると良いかと。

swift苦手なので、コードはあくまで雰囲気で。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.65%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る