Reputation: 14499
Because, Swift/Objective-C supports writing extensions, I write my "ViewModel" properties in an extension class on the model and use this extension in places where one normally uses a ViewModel.
I know extensions can't have stored properties. But most MVVM architectures don't recommend stored properties in ViewModel (except those used for caching) anyways.
My main trouble with maintaining separate ViewModel object is getting it in sync with the model. Yes, there are plenty of third-party frameworks to help sync using reactive programming techniques. But for what can be solved, by simply using an extension, why use a heavy framework achieve the same?
I've not hit a road block with my extensions based MVVM architecture. Have anyone of you tried this and moved on to a reactive programming architecture?
Upvotes: 3
Views: 2417
Reputation: 2770
My bad experience with the extensions approach was the basis for the first and most important part of my March 2016 talk at iOSoHo in New York. Most of what I said about extensions is not in the slides. There are several issues with the extension approach:
name
and then later adding firstNameOnly
, etc. Definitely a model can only ever conform to a protocol one way, if you're tempted to go that way. With a ViewModel these important cases become trivial. (In the talk I call "commands" because they perfectly match the Gang of Four Design Patterns definition of command; Design Patterns notes also known as Action, i.e. UIAlertAction.)
I take the approach that a "ViewModel" should be lightweight, immutable, and distributed through unidirectional data flow. They have stored properties but but this is just to move data around, the VMs themselves are immutable and disposable. This is similar to the approach mentioned by Facebook at iOSoHo March 2017, though I think they don't call them View Models, just lightweight objects. You could put more complex logic in there but really best to, at most, call out to more complex logic handled elsewhere.
One addition I think is key, my rule is that a "ViewModel", whatever you call it, should have no properties that can't be written by a programmer looking at wireframes. So a var dateString : String
not var date : NSDate
. This is my cheeky term in the slides, "Modal Object Attribute Transformer". But it's mnemonic for a serious point: A castle needs to be able to raise the drawbridge and carry on when under siege; a view needs to be fully functional when the network is cut off (or doesn't yet exist). You will have much easier time in so many scenarios than if your view can do that.
Just a few weeks ago I took this approach and was able to create multiple complex screens in about 4 days, working only from designs, that will eventually be populated by data from the network but currently without any model or networking layer whatsoever. When the data layer is ready, I can simply write some creational methods init(with: Model)
or better static func withModelforCase1(_ model: Model) -> ViewModel
and write the mapping in the creation method, then when the model is connected, replace static func debugCase1() -> ViewModel
with these creation methods. As the model evolves the compiler will throw errors here and only here; as the view evolves, adjust the ViewModel, and again the compiler will throw errors here and only here. No other code would need to be touched.
Extensions seem very elegant at the start, but actually create a tight coupling between models and views. Some kind of ViewModel approach is a robust system the needs of modern iOS apps--and modern iOS app development.
Upvotes: 3
Reputation: 57
Benefits of MVVM The ViewModel is an excellent place to put your validation logic for user input, view presentation logic, network requests. As a result, the ViewController files become far less bloated. Also, the View-ViewController component is completely isolated from the model. So during development, one developer can work on the UI part of the screen and another can take care of the logic for the screen, independently and concurrently. It is easy to redesign the UI without messing with the model logic since they are both completely isolated. As long as you link appropriate properties to the ViewModel, you can swap view components in and out. This gives more freedom to experiment with the UI. For Universal apps, both iPad and iPhone ViewControllers can interact with the same ViewModel. It’s easier to test. Developers can create unit tests for ViewModel and model without the View.
Upvotes: 1
Reputation: 49344
ViewModel
is supposed to be a different entity from architectural POV, not from code placement POV. Your approach to MVVM with extensions to model makes model know too much and violates SRP e.g. if model has some date attribute, view model would usually be used for formatting it using current locale. If Model is data storage it should only contain relevant data structures and no methods. If Model is a service (e.g. networking client) it should contain only relevant methods with minimal data transform (e.g. json to struct).
Also in my practice I sometimes have more than one VM to a single Model. If, say, I have a User
model with firstName
, lastName
and email
attributes, I may need fullName
property for displaying it in a table row (implemented in UserCellViewModel), but all three properties when displaying user information in detailed view (implemented in UserDetailViewModel). With extensions to model, all four properties (fullName
being implemented in extension) would be accessible in all contexts. Making controller consuming the ViewModel know as little as possible is a good thing (citation needed). This may be achieved in Objective-C where your extensions can have their own header/interface files, but you don't get this in Swift.
Upvotes: 1