MVVM Flashcards
mvvm involves three layers:
The model layer contains data access objects and validation logic. It knows how to read and write data, and it notifies the view model when data changes.
The view model layer contains the state of the view and has methods to handle user interaction. It calls methods on the model layer to read and write data, and it notifies the view when the model’s data changes.
The view layer styles and displays on-screen elements. It doesn’t contain business or validation logic. Instead, it binds its visual elements to properties on the view model. It also receives user inputs and interaction, and it calls methods on the view model in response.
How communication between layers looks like in mvvm?
“The view layer and model layer only communicate with the view model layer”
Model layer in mvvm
The model layer is responsible for all create, read, update and delete (CRUD) operations.
push-and-pull designs in model layer in mvvm
Push-and-pull designs require consumers to ask for data and wait for the response, which is the “pull” part. Consumers can also update model data and tell the model layer to send it, which is the “push” part.
and observe-and-push designs in model layer in mvvm
Observe-and-push designs require consumers to “observe” the model layer, instead of asking for data directly. Like push-and-pull designs, consumers can also update model data and tell the model layer to “push” it.”
Repository pattern diagram
“Repositories contain data access objects that can call out to a server or read from disk.”
The repository pattern provides a façade for networking, persistence and in-memory caching. This façade creates, reads, updates and deletes data on disk and in the cloud. The repository doesn’t expose to consumers how it retrieves or stores the data.
Repository structure and types of layers of data access through repository
Under the hood, the repository has multiple layers of data access. Each implementation of a repository may implement all or only one of these layers:
cloud-remote API
persistence-store layer
in-memory-cache layer
View layer
A view is a user interface for a screen. In MVVM, the view layer reacts to state changes through bindings to view model properties. It also notifies the view model of user interaction, like button taps or text input updates.
The purpose of the view is to render the screen. It knows how to layout and style the user interface elements, but doesn’t know anything about business logic.
In MVVM, you use one-way data binding to bind the UI elements from the view to the view model. This means the view model is the single source of truth. The view doesn’t update until the view model changes its state.
The view layer contains a hierarchy of views. Each parent view knows about its children and has access to their properties.
View model layer purpose
The purpose of the view model is to decouple the view controller from the view.
Idea of “pure mapping” in view model layers
View models take input signals and produce output signals, providing a clear boundary between view models and views.
Structure of view model
view state
task methods
dependencies
View state part of view model
View State is stored in the view model. The state is made up of public observable properties. Using RxCocoa, the user interface elements bind themselves to the observables when the view model is created.
task method part of view model
Task Methods perform tasks in response to user interactions. The methods do some work, such as calling a sign-in API, and then updating the view model’s state. The view knows if the state changes because the observables signal new data. You usually mark task methods as @objc methods, because you have to target-action pair on a UI Control.
Dependencies part of view model
Dependencies are passed to the view model through initializer injection. Task methods rely on the dependencies to communicate with other subsystems in the app, such as a REST API or persistent store. View models know how to use the dependencies, but have no knowledge of the underlying implementations.
Creating the view in MVVM
“The view knows how to style and layout its subviews, as well as hook up user interface elements to the view model observables
“In Koober, view controllers create the view and the view model inside loadView(). The view controller creates the view model first and passes it to the view. Since Koober creates view layouts in code, views can have a custom initializer.”
“If you use Interface Builder to create view controllers and views, view controllers would contain implicitly unwrapped view model variables. Dependency containers would inject view models into view controllers using property injection instead of initializer injection. View controllers would pass the view model to the View inside viewDidLoad() or awakeFromNib().
Container views in MVVM
“Each screen in Koober has a container view — a top-level view that contains other child views. The container view’s purpose is to build a complex screen out of modular views. Instead of throwing all the user interface into one massive view, keep your views small, focused and reusable.
The “view” in container view refers to a UIViewController and its UIView.”
Structuring container views
A dependency container initializes a container view with its child views. A container view adds and displays child views in its view hierarchy.
Child views limit the responsibility of the top-level container view. The number of child views needed depends on the screen’s complexity. Each child view is reusable and performs all its work independently.
“Communicating amongst view models
When view models signal out, they communicate what occurred rather than what to do. The application decides what to do. This provides flexibility — you can change how the app responds without changing the view model.
Collaborating view models
“Normally state changes in a view model update a view. Sometimes, those state changes affect the entire app. View models don’t know how to post app-wide notifications; they take inputs and produce outputs. One way for view models to communicate with the app is to call into another view model, forming a graph of view models.
View models have three ways to collaborate with each other:
Closures: For signaling out, view models take a closure as an initializer argument. The view model calls the closure when an event occurs.
Protocols: Each output signal is modeled with a single method protocol. Other view models that want to respond to outgoing signals must conform to the protocol. You should use a single protocol per signal; otherwise, you force the conformer to place all response logic into a single object.
Observables: For outgoing signals, a view model exposes a mutable observable subject that other view models can modify by pushing new state onNext(_:).
Navigating in mvvm
Model-driven navigation
System-driven navigation
Combination
Model-driven navigation in mvvm
In model-driven navigation, view models contain a view enum describing all possible navigation states. The system observes this and navigates to the next screen when the value changes.
Container views and container view models handle navigation for their children. Children view models signal out to the container view model that handles navigation at the top level.
Child views can signal out in two ways:
Collaborating view models signal to each other when a view enum value changes. Child view models get injected with a higher level view model and call task methods when navigation should occur.
Shared observable view state holds a mutable Observable subject property with the current view enum value. A dependency container injects child view models with the Observable subject. Any child view model can push a new view enum value. The container view model observes the value and navigates to the next screen when it changes.
System-driven navigation
System-driven navigation is any navigation managed by the system. For example, gestures that trigger scroll view page navigation, or tapping a Back button in a navigation stack, automatically navigate the user to the previous screen.
“In pure MVVM, you override all these gestures, and the view model handles the user interaction. For most apps, this is overkill. A better option is to work with the system and leverage what’s already designed for you by Apple. As soon as an MVVM implementation causes friction with the built-in system paradigms, consider using an MVVM implementation that combines model-driven navigation and system-driven navigation
Combination navigation in mvvm
You can use built-in, system-driven navigation to your advantage, while still implementing an MVVM architecture. For example, you can use model-driven navigation to move a navigation stack forwards and use system-driven navigation to move backwards.
Koober’s onboarding flow uses a combination of model-driven and system-driven navigation.
The onboarding view model switches between three states: welcome, sign in, and sign up. Tapping the Sign In button on the welcome screen changes the view model state to “sign in.” The onboarding view reacts to the change, and it pushes the sign-in screen onto the navigation stack. Tapping the Back button on the sign-in screen’s navigation bar uses system-driven navigation to pop the screen from the stack