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")
ビューコントローラとビューモデルが相互に作用する方法の問題は完全には解決されませんが、ネットワークコードが確実に単一障害点に移動します。
モデルは単なるデータ表現でなければならないので、私は同意しません。データフェッチメソッドがクラスメソッドであり、インスタンスメソッドではない限り、動作することはできますが。 – barndog
私はPostSearchのようなネットワークコードを持ったモデルについて考えていましたが、Postモデルにはネットワークコードも含めるべきではありません。 – Ionut