Arquitectura de networking genérica MVVM

Desarrollo aplicaciones iOS usando el paradigma Model View ViewModel para estructurar mis controlleres de vista y representar sus datos. Que junto con ReactiveCocoa es una herramienta poderosa; los controlleres de vista se vuelven less hinchados, los models de vista son más fáciles de probar y hay una clara separación de preocupaciones.

El único problema que tengo con esta architecture en particular es que, al igual que MVC, todavía no hay un lugar o una estructura clara para estructurar el código de networking. Tomemos el siguiente ejemplo trivial:

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() } } } 

Entonces, en mi punto de vista controller puedo hacer algo:

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

Para mí, parece que todo el punto de usar MVVM fue no exponer las vistas y ver el controller (a lo que llamo la capa de presentación de vista) a cualquier código de networking, pero todavía necesito una manera de poder observar que el nuevo contenido ha sido Se buscó sin conocer los detalles, solo que se produjo una extracción exitosa. Me imagino que sería algo así:

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

Al mismo time, tampoco quiero perder la capacidad de unir señales y señalar a los productores a properties mutables en mi uso de <~ .

 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 } } 

Este método de hacer esto es un poco mejor, pero todavía usa efectos secundarios para enviar un próximo evento al observador de señal y si está utilizando una class base ViewModel común, debe exponer a ese observador para que las subclasss puedan usarlo.

Estoy buscando cualquier mejora que pueda hacerse en la architecture MVVM, ya sea cambios en la architecture misma, de modo que ya no sea MVVM y facilite la creación de networkinges de una manera mejor y más genérica o incluso algún tipo de protocolo base genérico para models de vista que Abstrae todo el process de distancia.

Para mí, ser lo más genérico posible y exponer la menor información posible sobre el model de vista es key. Idealmente, me gustaría que cada controller de visualización interactúe con el model de visualización exactamente de la misma manera en lo que respecta a cómo funciona la networking.

EDITAR:

Según la sugerencia de at @ lonut, moví parte del código de networking a mis classs model, pero solo como methods estáticos:

 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 } } 

De esta forma, los models pueden implementar llamadas de networking a su antojo, lo que tiene el beneficio de abstraer los detalles de la implementación, como las llamadas específicas de la networking Moya, el mapeo de los objects de respuesta, etc.

Imagine que tiene un model de User :

 User.get("myUserID") 

No resuelve por completo el problema de cómo el controller de vista y el model de vista deben interactuar entre sí, pero definitivamente mueve el código de networking a un solo punto de falla.

No estoy muy avanzado en el uso de MVVM o RAC pero de lo que he jugado con el código de networking debe estar en la parte del model, entonces hay un método que observa los resultados en la parte del model de vista (algo así como "fetchPosts ()" ) y en la parte de vista se llama al método fetchPosts. Te recomiendo esta publicación de blog para get mucha más información.