Middle
Tell us about the MVVM (Model-View-ViewModel) pattern.
sobes.tech AI
Answer from AI
MVC (Model-View-Controller).
| Component | Description | Responsibility |
|---|---|---|
| Model | Represents the data and business logic of the application. It is independent of View or ViewModel. | Data management, business rules, interaction with server/database. |
| View | User interface. Displays data and passes user actions to ViewModel. Contains no data processing logic. | Displaying information, handling user events (taps, swipes, etc.). |
| ViewModel | Mediator between Model and View. Provides View with data in a display-friendly format and handles user actions, interacting with Model. It does not know whether View is used or not, only communicates through data binding. | Transforming data from Model for View, handling user interactions, business logic unrelated to UI. |
Main principles:
- Data Binding: Binding data between View and ViewModel. When data in ViewModel changes, View updates automatically, and vice versa.
- Testability: ViewModel is easy to test as it does not depend on UI framework.
- Separation of Concerns: Clear separation of component roles.
Advantages:
- Improved testability.
- Cleaner separation of responsibilities.
- Simplifies codebase when working with complex UI.
Disadvantages:
- May be excessive for simple applications.
- Complexity of implementing Data Binding without third-party frameworks (e.g., RxSwift, Combine).
Example structure:
// Model
struct User {
let name: String
let age: Int
}
// ViewModel
class UserViewModel {
private let user: User
init(user: User) {
self.user = user
}
var displayName: String {
return user.name
}
var displayAge: String {
return "\(user.age) years"
}
// Method to handle user actions
func userTapped() {
print("User \(user.name) tapped")
// Possibly interacts with Model or other logic
}
}
// View (UIViewController)
class UserViewController: UIViewController {
private var viewModel: UserViewModel!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var ageLabel: UILabel!
func configure(with viewModel: UserViewModel) {
self.viewModel = viewModel
updateUI()
}
private func updateUI() {
// Data Binding (manual example)
nameLabel.text = viewModel.displayName
ageLabel.text = viewModel.displayAge
}
@IBAction func tapGestureRecognized(_ sender: Any) {
viewModel.userTapped()
}
}