SwiftUI

MVVM: Model - View - ViewModel

ContentModel.swift

import Foundation

struct ContentModel {
    var content: String
  
    mutating func performIntent() {
        content = "Hello " + content
    }
}

ContentViewModel.swift

import SwiftUI

class ContentViewModel: ObservableObject {
  @Published private(set) var contentModel: ContentModel
  
  init(content: String) {
    contentModel = ContentModel(content: content)
  }
  
  // MARK: Intent(s)
  func performIntent() {
    contentModel.performIntent()
  }
}

ContentView.swift

import SwiftUI

struct ContentView: View {
    @ObservedObject var contentViewModel: ContentViewModel
    
    var body: some View {
        Text(contentViewModel.contentModel.content)
          .onTapGesture {
            contentViewModel.performIntent()
          }
          .frame(width: 100, height: 100)
    }
}

MVVM


Views and Modifiers

  • Views
    • Image Assets
    • Color Assets
  • Modifiers

Common Views

Text("Hello SwiftUI")
  .font(.subheadline)
  .foregroundColor(.secondary)

Text("Fancy")
  .font(.system(size: 20, weight: .bold, design: .rounded))
Image(update.image)
  .resizable()
  .aspectRatio(contentMode: .fit)

View Combiners

HStack { 
  
}
VStack { 

}
ZStack { 
  RoundedRectangle(cornerRadius: 10)
  Text("🍏")
}
ForEach(image) { image in
  Image(image)
    .resizable()
    .frame(height: 100)
}

Modifiers

Full width text

Text("")
  .frame(maxWidth: .infinity, alignment: .leading)

Modal View

Button(action: { self.sheetPresented.toggle() }) {
  Text("Button")
}
.sheet(isPresented: $sheetPresented) {
  ContentView()
}

Data flow primitives / Properties

@State var showUpdate = false
@Binding var showProfile: Bool
@Published var updates: [Update] = updateData
@ObservedObject var store = UpdateStore()

Binding properties denoted by $-prefix, e.g.

ViewWithBinding(bindingVariable: $variable)

Combine

Store Class

import SwiftUI
import Combine

class UpdateStore: ObservableObject {
  @Published var updates: [Update] = updateData
}
@ObservedObject var store = UpdateStore()

// store.updates

Binding state variables in a subview

struct Home: View {
  @State var state: Bool

  var body: some View {
    // …
    ExtractedView(subviewState: $state)
    // …
  }
}
struct ExtractedView: View {
  @Binding var subviewState: Bool

  // …
}

@State

struct ContentView: View { 
  @State var dragOffset: CGSize

  // ...
}

Observable Object

class ViewModel: ObservableObject { 
  @Published private var model
}
struct ContentView: View { 
  @ObservedObject var viewModel: ViewModel

  // ...
}

Geometry

Positioning

  • .offset Modifier (aka relative position)
  • .position Modifier (aka absolute position)
  • Alignment
    • .leading
    • .trailing
    • .trailing

SwiftUI Coordinate Spaces

  • .global
  • .local
  • .named("XYZ")

Modifier: View().coordinateSpace("XYZ")

Detect Screen Size

let screen = UIScreen.main.bounds
screen.height
screen.width

GeometryReader

GeometryReader { geometry in
  // geometry.frame(in: .global).minX
  // geometry.size
}

Animation

Implicit Animation

Explicit Animation

Transitions



Gestures