up:: Swift

SwiftUI fundamentals course

Course: https://youtu.be/b1oC7sLIgpI?feature=shared&t=18755

  • Stacks
    • Horizontal/Vertical: HStack, VStack
    • Background/Foreground: ZStack
  • Modifiers wrap a View in another View. So the order of modifiers matters.
    • Like wrapping an element in divs


Are like windows


Views are kind of like components in Nuxt/Vue.

  • You can make a variable reactive with @State (like Vue’s ref)


You can bind a variable with @Binding and $varName. Whenever the variable in the child changes, it sets that variable on the parents.

This is similar to v-model in Vue.


Interable needs to conform to Hashable. The Fundation types like string, int etc are all hashable

struct Framework: Hashable, Identifiable {
    let id = UUID()
    let name: String
    let imageName: String
    let urlString: String
    let description: String
            ForEach(MockData.frameworks) { framework in
                FrameworkTitleView(name: framework.name, imageName: framework.imageName)

Basic button

            Button(action: {
            }, label: {
                Text("Learn more")
                    .frame(width: 280, height: 50)

Use Apple’s defaults

            Button(action: {
                isShowingSafariView = true
            }, label: {
                AFButton(title: "Learn more")

Create a big struct with all error messages

struct AlertItem {
    let title: String
    let message: String
    let dismissButtonText: String
struct AlertContext {
    static let invalidDeviceInput = AlertItem(title: "my error", message: "Hello there", dismissButtonText: "Close")

You create one alert and then pass in different AlertItem content.

Data-driven navigation. Based on data type, you show different screens.

    var body: some View {
        NavigationStack {
            ScrollView {
                LazyVGrid(columns: columns) {
                    ForEach(MockData.frameworks) { framework in
                        NavigationLink(value: framework) {
                            FrameworkTitleView(framework: framework)
                .navigationTitle(" Frameworks")
                .navigationDestination(for: Framework.self) { framework in
                    FrameworkDetailView(framework: framework)


  • Model
  • View
  • ViewModel


That’s the data, eg. the framework model


That’s the display. There should be no logic here. They should be as dump as possible. For example, ternary operators.


This is where the logic sits. Only required if it’s dynamic. If there is a change in view logic.

ObservableObject means this class can “broadcast” data

  • In ObservableObject, you need to use @Published to broadcast the data
  • In the View, you need to use @StateObject to get those changes
    • There you also need to create a new one (with ())
  • Passing one in: observeObject

In the ViewModel:

import SwiftUI
final class FrameworkGridViewModel: ObservableObject {
    @Published var selectedFramework: Framework?

In the View:

@StateObject var viewModel = FrameworkGridViewModel()


Objects (structs) get destroyed and rerendered all the time. @StateObject signifies that this data should be kept during re-renders.

This is going to stay alive, while the parent View will be destroyed and created.

Listening to state changes

final class FrameworkGridViewModel: ObservableObject {
    var selectedFramework: Framework? {
        didSet {
            isShowingDetailView = true
    @Published var isShowingDetailView = false

Each component into their own file

Move each component into their own file. That way, you can preview just that component and debug it.


Every time you add a modifier, you wrap all existing modifiers in a new View. So the order matters.

Like in CSS, children inherit modifieres from parents. These are called “Environment modifiers”.


For example, a ZStack or a VStack. There are only specific things you can write within a Viewbuilder.

View performance

Views are structs. They don’t inherit, so creating and destroying them is fast.

The Views are broken out into a View tree. The diff-ing algorithm only changes what is bound reactively.## Basic NavigationView

    var body: some View {
        NavigationView {
            ScrollView {
                LazyVGrid(columns: columns) {
                    ForEach(MockData.frameworks) { framework in
                        FrameworkTitleView(framework: framework)
            }.navigationTitle(" Frameworks")

Directory structure

/UIKit Components