Model–View–View Model (MVVM)
MVVM is a structural pattern that focuses on three pieces:
-
Model: In the most practical sense, any data to bring on screen. Could be mutable by the user, or static. (Similar to MVC).
-
View: In the strictest sense, the
NSView
orUIView
subclass, orSwiftUI.View
component that draws pixels on screen to somehow visualize the model. (Similar to MVC). -
View Model: A representation of the Model that’s designed to cooperate with the View. In SwiftUI, Combine, RxSwift, this is often reactive, driving the UI with live changes.
View Model as Data Transfer Object
The View Model can be a dumb data-transfer object (DTO) that is coupled to the view: when you need to display a person’s age in a text field, you declare age: String
to match the text field’s expectation.
This is an important change already and removes a big burden from the Controller: By assembling a special model for consumption by the view, you isolate points for change. You only need to change 1 place where the “true Model” becomes the “View Model”. This decouples the View from the Model through a layer of abstraction.
The View doesn’t need to know the Model, and it cannot even by accident change database entities, and the Model doesn’t need to worry about being displayable.
Assembly of this View Model could be done by a Presenter, a term also used in the VIPER architectural pattern.
Reactive View Models and Cocoa Bindings
The View Model can also be a two-way live view into the app’s overall state, and even some persistence mechanism like a database or cloud storage. The View Model then exposes reactive bindings like @Published
properties instead of the usual.
Interestingly, reactive bindings in View Models echo Key–Value Coding (KVC) and Key–Value Observation (KVO) that was possible in Objective-C, and still is if you use dynamic dispatch via @objc
. Only KVO was brittle and required runtime checks since it came with no compile time guarantees.
In the extreme case, a mutable reactive View Model is just the modern equivalent of a Core Data NSManagedObject
with (macOS exclusive) Cocoa Bindings of UI components directly into the data store. With all its downsides.