Skip to content

WWDC20 Dub Dub Diary, Part 5 - Data Essentials in SwiftUI

3 min read

The last day of WWDC20, ended well with many amazing sessions. This day had an interesting session, which many of developers waited. For the last article of WWDC20, let’s see the details and my last thoughts.

Data Essentials in SwifUI

This session talks about how to deal data in SwiftUI. How to design your model, and techniques for your app. They explain three key questions when starting a new view in SwiftUI, which in this session answers all that questions.

@State, @Binding

While creating a view, we need to know what data the view needs to render. Does the view displays the data or manipulate the data? If you are just showing the data, use let properties.

struct BookCard : View {
    let book: Book
    let progress: Double

    var body: some View {
        HStack {
            Cover(book.coverName)
            VStack(alignment: .leading) {
                TitleText(book.title)
                AuthorText(book.author)
            }
            Spacer()
            RingProgressView(value: progress)              
        }
    }
}

What if you are manipulating the data? Use @State and @Binding to preserve and seamlessly update the Source of Truth. @State creates a new Source of Truth, and @Binding is for sharing right access to any Source of Truth.

struct EditorConfig {
    var isEditorPresented = false
    var note = ""
    var progress: Double = 0
    mutating func present(initialProgress: Double) {
        progress = initialProgress
        note = ""
        isEditorPresented = true
    }
}

struct BookView: View {
    @State private var editorConfig = EditorConfig()
    func presentEditor() { editorConfig.present() }
    var body: some View {

        Button(action: presentEditor) {  }
        ProgressEditor(editorConfig: $editorConfig)

    }
}

struct ProgressEditor: View {
    @Binding var editorConfig: EditorConfig

        TextEditor($editorConfig.note)

}

ObservableObject, @Published, @StateObject, @EnvironmentObject

/// The current reading progress for a specific book.
class CurrentlyReading: ObservableObject {
    let book: Book
    @Published var progress = ReadingProgress()
    @Published var isFinished = false

    var currentProgress: Double {
        isFinished ? 1.0 : progress.progress
    }
}

struct ReadingProgress {
    struct Entry : Identifiable {
        let id: UUID
        let progress: Double
        let time: Date
        let note: String?
    }

    var entries: [Entry]
}

struct BookView: View {
    @ObservedObject var currentlyReading: CurrentlyReading

    var body: some View {
        VStack {
            BookCard(
                currentlyReading: currentlyReading)

            HStack {
                Button(action: presentEditor) { /* … */ }
                    .disabled(currentlyReading.isFinished)

                Toggle(
                    isOn: $currentlyReading.isFinished
                ) {
                    Label(
                        "I'm Done",
                        systemImage: "checkmark.circle.fill")
                }
            }
            //…
        }
    }
}

ObservableObject lets you connect your views to your data model. It is a data dependency surface for SwiftUI’s Views.

@Published is used on to the property of the type that conforms to ObservableObject, which SwiftUI will be notified of their changes.

They are three types of ObservableObject, and I recommend seeing the documentation for more information.

State and Data Flow - Apple Developer Documentation

Source of Truth Lifetime

There are two property wrapper that can automatically save and restore State. Both are lightweight Storage you use in conjunction with your model.

@SceneStorage is a per-Scene scoped property wrapper. SwiftUI manage to read and write data. It is only accessible from within Views.

@AppStorage is a app-scoped global storage with is persisted using user defaults. It is usable anywhere, you can access it from within your App or from your View.

// SceneStorage
struct ReadingListViewer: View {
    @SceneStorage("selection") var selection: String?

    var body: some View {
        NavigationView {
            ReadingList(selection: $selection)
            BookDetailPlaceholder()
        }
    }
}

// AppStorage
struct BookClubSettings: View {
    @AppStorage("updateArtwork") private var updateArtwork = true
    @AppStorage("syncProgress") private var syncProgress = true

    var body: some View {
        Form {
            Toggle(isOn: $updateArtwork) {
                //...
            }

            Toggle(isOn: $syncProgress) {
                //...
            }
        }
    }
}

Performance Tips

Data Essentials in SwiftUI - WWDC 2020 - Videos - Apple Developer

Wrap Up

This WWDC20 was all new, interesting experience. Meeting so many engineers, new code-along sessions, new online labs, letting all the developers watch the session without getting the tickets. It was also my first remote conference, watching developers communicate online made the conference more connected. Although, I hope Apple runs WWDC21 in person.


Share this post on:

Previous Post
나의 새로운 Mac 설정 목록 (Setup my personal Mac)
Next Post
WWDC20 Dub Dub Diary, Part 4 - Swift type inference, writing tests to fail