2016-03-08 6 views
8

Model View ViewModelパラダイムを使用してiOSアプリケーションを開発し、ビューコントローラを構成し、そのデータを表現します。 ReactiveCocoaとの組み合わせは、強力なツールです。ビューコントローラの膨らみが少なくなり、ビューモデルのテストが容易になり、懸念事項が明確に分離されます。MVVM汎用ネットワーキングアーキテクチャ

私がこの特定のアーキテクチャで持っている1つの問題は、MVCのように、ネットワーキングコードを構造化する明確な場所や方法がまだないことです。 次些細な例を見てみましょう:私のビューコントローラで次に

class HomepageViewModel { 
    var posts: MutableProperty<[Post]> = MutableProperty([]) 

    func fetchPosts() -> SignalProducer<[Post], NSError> { 
     return SignalProducer { observer, disposable in 
      // do some networking stuff 
      let posts = .... 
      observer.sendNext(posts) 
      observer.sendCompleted() 
     } 
    } 
} 

どこかに私が行うことができます。

self.viewModel.posts <~ self.viewModel.fetchPosts().on(next: { _ in self.collectionView.reloadData() }) 

私にMVVMを使用しての全体のポイントは、ビューとビューを公開していないことだったようにそれは感じていますコントローラ(ビュープレゼンテーション層と呼ぶもの)をネットワーキングコードに変換することはできますが、新しいコンテンツがフェッチされたことを観察できる方法が必要です。私はまた私が<~を使用して変更可能なプロパティに信号と信号の生産を結合する能力を失いたくない、同時に

self.viewModel.contentUpdatedSignal.observeNext { _ in self.collectionView.reloadData() } 

:私はのようになります想像します。

class ViewModel { 
    let someProperty = MutableProperty<[SomeModel]>([]) 
    var (contentUpdatedSignal, observer) = Signal.pipe() 
    init() { 
     self.someProperty <~ self.fetchContent().on(next: { _ in observer.sendNext() } 
    } 

    func fetchContent() -> SignalProducer<[SomeModel], NSError> { 
     // do some fun stuff 
    } 
} 

これを実行するこの方法は少し良いですが、それはまだ信号オブザーバに次のイベントを送信するために副作用を使用して、共通ViewModel基本クラスを使用している場合、あなたはので、オブザーバを公開する必要がありそのサブクラスはそれを使用することができます。

私はMVVMアーキテクチャにできる改善点を探しています。アーキテクチャ自体を変更してMVVMではなくなり、より一般的なやり方で、あるいは何らかの汎用ベースプロトコルプロセス全体を抽象化するビューモデルのために。

可能であればビューモデルについての情報をできるだけ公開しないように、可能な限り一般化することが重要です。理想的には、どのようにネットワークが動作するかに関して、まったく同じ方法で、各ビューコントローラにビューモデルと対話させたいと思います。モデルは意志でネットワーク呼び出しを実装することができるこの方法を

import Foundation 
import ReactiveCocoa 
import Moya 

protocol RESTModel { 
    typealias Model 

    static func create(parameters: [NSObject: AnyObject]?) -> SignalProducer<Model, Moya.Error> 
    static func find() -> SignalProducer<Model, Moya.Error> 
    static func get(id: String) -> SignalProducer<Model, Moya.Error> 
    static func update(id: String) -> SignalProducer<Model, Moya.Error> 
    static func remove(id: String) -> SignalProducer<Model, Moya.Error> 

} 

extension RESTModel { 
    static func create(parameters: [NSObject: AnyObject]? = nil) -> SignalProducer<Self.Model, Moya.Error> { 
     return SignalProducer.empty 
    } 
    static func find() -> SignalProducer<Self.Model, Moya.Error> { 
     return SignalProducer.empty 
    } 
    static func get(id: String) -> SignalProducer<Self.Model, Moya.Error> { 
     return SignalProducer.empty 
    } 
    static func update(id: String) -> SignalProducer<Self.Model, Moya.Error> { 
     return SignalProducer.empty 
    } 
    static func remove(id: String) -> SignalProducer<Self.Model, Moya.Error> { 
     return SignalProducer.empty 
    } 
} 

EDIT:@のlonutの提案で

パー、私は私のモデルクラスにネットワークコードの一部を移動するだけの静的メソッド特定のMoyaネットワーク呼び出し、応答オブジェクトのマッピングなどの実装の詳細を抽象化する利点があります。

Userモデル:

があるとします。
User.get("myUserID") 

ビューコントローラとビューモデルが相互に作用する方法の問題は完全には解決されませんが、ネットワークコードが確実に単一障害点に移動します。

答えて

1

私はMVVMやRACを使っていませんが、ネットワーキングコードで演奏したものはモデル部分にあるはずですが、ビューモデル部分の結果を観察する方法があります。 fetchPosts() ")、ビュー部分でfetchPostsメソッドが呼び出されます。私はあなたにもっと多くの情報のためにthis blog postをお勧めします。

+0

モデルは単なるデータ表現でなければならないので、私は同意しません。データフェッチメソッドがクラスメソッドであり、インスタンスメソッドではない限り、動作することはできますが。 – barndog

+0

私はPostSearchのようなネットワークコードを持ったモデルについて考えていましたが、Postモデルにはネットワークコードも含めるべきではありません。 – Ionut