Common MVVM Network Architecture

I am developing iOS applications using the Model View ViewModel paradigm to structure view controllers and present their data. This combined with ReactiveCocoa is a powerful tool; view controllers are becoming less bloated, view models are easier to test, and there is a clear separation of problems.

The only problem I encounter with this particular architecture is that, like MVC, there is still no clear place or way to structure network code. Take the following trivial example:

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

Then, in my opinion, the controller somewhere I can do:

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

It seems to me that the whole purpose of using MVVM was not to expose the viewer and viewer to the controller (what I call the presentation presentation level) to anyone from the network code, but I still need a way to be able to observe what new content was obtained without specific knowledge, a successful selection had just taken place. I would suggest that it would look something like this:

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

At the same time, I also do not want to lose the ability to bind signals and signal producers to mutable properties when using <~ .

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

This way of doing this is a little better, but it still uses side effects to dispatch the next event in the signal observer, and if you use the common base class ViewModel , you must expose this observer so that subclasses can use it.

I am looking for any improvements that can be made to the MVVM architecture, or changes to the architecture itself so that it is no longer MVVM and does not facilitate network interaction in a more universal way or even some kind of generic base protocol for viewing models that abstract the whole process .

For me, as general as possible, while you show as little information as possible about the presentation model, this is the key. Ideally, I would like each view controller to interact with the view model in exactly the same way that the network works.

EDIT:

Per at the suggestion of @lonut, I moved part of the network code to my model classes, but only as static methods:

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

Thus, models can make network calls at their discretion, which allows us to abstract from implementation details, such as specific Moya network calls, display of response objects, etc.

Imagine you have a User model:

 User.get("myUserID") 

It does not completely solve the problem of how the view controller and the view model should interact with each other, but it definitely translates the network code into one point of failure.

+8
ios architecture swift mvvm network-programming
source share
1 answer

I am not very advanced in using MVVM or RAC, but from what I was playing with network code, it should be in the part of the model, then there is a method that monitors the results in the part of the view model (something like "fetchPosts" () " ), and the fetchPosts method is called in the view part. I recommend this blog post to you for more details.

+1
source share

All Articles