2020 SwiftSystem ServicesSwiftUI & UI Frameworks
WWDC20 · 36 min · Swift / System Services / SwiftUI & UI Frameworks
Data Essentials in SwiftUI
Data is a complex part of any app, but SwiftUI makes it easy to ensure a smooth, data-driven experience from prototyping to production. Discover @State and @Binding, two powerful tools that can preserve and seamlessly update your Source of Truth. We’ll also show you how ObservableObject lets you connect your views to your data model. Learn about some tricky challenges and cool new ways to solve them — directly from the experts! To get the most out of this session, you should be familiar with SwiftUI. Watch “App essentials in SwiftUI” and "Introduction to SwiftUI"
Watch at developer.apple.com ↗Code shown on screen · 14 snippets
BookCard
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)
}
}
} EditorConfig
struct EditorConfig {
var isEditorPresented = false
var note = ""
var progress: Double = 0
mutating func present(initialProgress: Double) {
progress = initialProgress
note = ""
isEditorPresented = true
}
}
struct BookView: View {
private var editorConfig = EditorConfig()
func presentEditor() { editorConfig.present(…) }
var body: some View {
…
Button(action: presentEditor) { … }
…
}
} ProgressEditor
struct EditorConfig {
var isEditorPresented = false
var note = ""
var progress: Double = 0
}
struct BookView: View {
private var editorConfig = EditorConfig()
var body: some View {
…
ProgressEditor(editorConfig: $editorConfig)
…
}
}
struct ProgressEditor: View {
var editorConfig: EditorConfig
…
TextEditor($editorConfig.note)
…
} CurrentlyReading
/// The current reading progress for a specific book.
class CurrentlyReading: ObservableObject {
let book: Book
var progress: ReadingProgress
// …
}
struct ReadingProgress {
struct Entry : Identifiable {
let id: UUID
let progress: Double
let time: Date
let note: String?
}
var entries: [Entry]
} BookView
struct BookView: View {
var currentlyReading: CurrentlyReading
var body: some View {
VStack {
BookCard(
currentlyReading: currentlyReading)
//…
ProgressDetailsList(
progress: currentlyReading.progress)
}
}
} CurrentlyReading with isFinished
class CurrentlyReading: ObservableObject {
let book: Book
var progress = ReadingProgress()
var isFinished = false
var currentProgress: Double {
isFinished ? 1.0 : progress.progress
}
} BookView with Toggle
struct BookView: View {
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")
}
}
//…
}
}
} CoverImageLoader
class CoverImageLoader: ObservableObject {
public private(set) var image: Image? = nil
func load(_ name: String) {
// …
}
func cancel() {
// …
}
deinit {
cancel()
}
} BookCoverView
struct BookCoverView: View {
var loader = CoverImageLoader()
var coverName: String
var size: CGFloat
var body: some View {
CoverImage(loader.image, size: size)
.onAppear { loader.load(coverName) }
}
} ReadingListViewer (Bad)
struct ReadingListViewer: View {
var body: some View {
NavigationView {
ReadingList()
Placeholder()
}
}
}
struct ReadingList: View {
var store = ReadingListStore()
var body: some View {
// ...
}
} ReadingListViewer (Good)
struct ReadingListViewer: View {
var body: some View {
NavigationView {
ReadingList()
Placeholder()
}
}
}
struct ReadingList: View {
var store = ReadingListStore()
var body: some View {
// ...
}
} App-wide Source of Truth
@main
struct BookClubApp: App {
private var store = ReadingListStore()
var body: some Scene {
WindowGroup {
ReadingListViewer(store: store)
}
}
} SceneStorage
struct ReadingListViewer: View {
("selection") var selection: String?
var body: some View {
NavigationView {
ReadingList(selection: $selection)
BookDetailPlaceholder()
}
}
} AppStorage
struct BookClubSettings: View {
("updateArtwork") private var updateArtwork = true
("syncProgress") private var syncProgress = true
var body: some View {
Form {
Toggle(isOn: $updateArtwork) {
//...
}
Toggle(isOn: $syncProgress) {
//...
}
}
}
} Resources
Related sessions
-
26 min -
23 min -
40 min -
19 min -
15 min -
28 min -
55 min -
34 min