Skip to content

Instantly share code, notes, and snippets.

@ivanornes
Created August 10, 2022 20:19
Show Gist options
  • Save ivanornes/571a0cc5958b78fd18cc46eaf251e568 to your computer and use it in GitHub Desktop.
Save ivanornes/571a0cc5958b78fd18cc46eaf251e568 to your computer and use it in GitHub Desktop.
//
// ContentView2.swift
// MVVM
//
// Created by Ivan Ornes on 10/8/22.
//
import SwiftUI
class Model: ObservableObject { // Rich domain
@Published var counter: Int = 0
func increment() {
counter += 1
}
}
// <GrandChildView: View> Avoids requiring AnyView
struct ChildView<GrandChildView: View>: View {
private let vm: ChildViewModel
private let grandChildView: GrandChildView
init(vm: ChildViewModel, grandChildView: GrandChildView) {
self.vm = vm
self.grandChildView = grandChildView
}
var body: some View {
VStack {
grandChildView
}
}
}
class GrandChildViewModel: ObservableObject {
private let model: Model
init(model: Model) {
self.model = model
}
func increment() {
model.increment()
}
}
struct GrandChildView: View {
private let vm: GrandChildViewModel
init(vm: GrandChildViewModel) {
self.vm = vm
}
var body: some View {
VStack {
Button("Increment from GrandChildView") {
vm.increment()
}
}
}
}
class ContentViewModel: ObservableObject {
private let model: Model
@Published var counter: String = "0"
init(model: Model) {
self.model = model
_ = model.$counter.sink {
// Adapt domain model to what the UI should show
self.counter = "\($0)"
}
}
func increment() {
model.increment()
}
}
class ChildViewModel: ObservableObject {
private let model: Model
init(model: Model) {
self.model = model
}
}
struct ContentView<ChildView: View>: View {
let vm: ContentViewModel
let childView: ChildView
var body: some View {
VStack {
// Follow the Demeter law, do not go too deep in the dependency dependencies
// Uses the formatted counter of the view model
Text(vm.counter)
.font(.largeTitle)
Button("Increment from ContentView") {
vm.increment()
}
childView
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let model = Model()
let grandChildView = GrandChildView(vm: GrandChildViewModel(model: model))
let childView = ChildView(vm: ChildViewModel(model: model), grandChildView: grandChildView)
ContentView(vm: ContentViewModel(model: model), childView: childView)
}
}
//
// MVVMApp.swift
// MVVM
//
// Created by Ivan Ornes on 10/8/22.
//
import SwiftUI
@main
struct MVVMApp: App {
@StateObject private var model = Model()
var body: some Scene {
WindowGroup { // App composition
let grandChildView = GrandChildView(vm: GrandChildViewModel(model: model))
let childView = ChildView(vm: ChildViewModel(model: model), grandChildView: grandChildView)
ContentView(vm: ContentViewModel(model: model), childView: childView)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment