WWDC Quick Look 💓 By SwiftGGTeam
Introduction to SwiftUI

Introduction to SwiftUI

Watch original video

Highlight

Apple uses the Sandwiches example to build a universal SwiftUI App for iOS, iPadOS and macOS from scratch, showing View composition, source of truth,@State@StateObject, list editing, animations, and Xcode previews into a declarative development process.

Core Content

Many introductory UI tutorials start with a list of controls. The method of this session is more straightforward: open Xcode, create a new multi-platform project, and then build an app that records sandwiches step by step. Developers first see that the code and canvas are updated simultaneously, and then see how lists, navigation, detail pages, states, animations, data models, and previews are connected to the same line.

In traditional UI development, view objects often take on too many responsibilities. Developers need to create objects, set properties, respond to events, maintain navigation and list state, and manually handle refresh timing. The entry point of SwiftUI is to write the interface as a value:bodyDescribe the interface that the current data should present, and the framework will retrieve a new description after the data changes.

The Sandwiches example just covers the basic skeleton of a real app. The list starts from a hard-coded cell and accessesIdentifiableAfter the model, it becomes a data-driven list; used on the details page@StateControl image scaling; root data is upgraded from static array toObservableObject;Finally, use the preview to check out dark mode, dynamic fonts, Arabic, and right-to-left layout.

This session is not an overview of all new SwiftUI APIs in 2020. It is more like an introductory path: first understand that View is very light, and feel free to dismantle small components; then understand the source of truth, and know where the state should be placed; and finally treat Xcode preview as part of the development cycle, rather than a remediation tool after running the App.

Detailed Content

View is a lightweight value

(17:18) Kyle pauses the presentation midway through to explain the SwiftUI View model.Viewis consistent withViewProtocol struct, not inheritedUIViewSuch a base class also does not own a bunch of framework-allocated storage. The framework collapses the view hierarchy into a data structure suitable for rendering, so developers can break the interface into small single-purpose views.

struct SandwichDetail: View {
    let sandwich: Sandwich

    var body: some View {
        Image(sandwich.imageName)
            .resizable()
            .aspectRatio(contentMode: .fit)
    }
}

Key points:

  • SandwichDetailis a struct, the stored input is onlysandwich
  • bodyyesViewThe only attribute required by the protocol, responsible for returning the interface description. -Image(sandwich.imageName)Create an image view from an image name in the model. -.resizable()and.aspectRatio(contentMode: .fit)are decorators, they return a new View description.
  • This code comes from the official snippet and relies on the session imported earlier.SandwichModel.

View becomes larger through combination

(18:30) The combination method of SwiftUI is consistent with the first half of the demo:VStackArrange text vertically,HStackArrange pictures and text horizontally,ListWrap multiple lines,NavigationLinkThen connect the cell to the details page.SandwichDetailThe same pattern can be seen in , where the image, zoom, and scale controls are combined into a new View.

struct SandwichDetail: View {
    let sandwich: Sandwich

    var body: some View {
        Image(sandwich.imageName)
            .resizable()
            .aspectRatio(contentMode: .fit)
    }
}

Key points:

  • ImageresizableandaspectRatioSynthesize a details page image area during rendering.
  • The decorator participates in constructing a new View description and does not follow the path of modifying existing objects afterwards.
  • whenbodyWhen reread, SwiftUI will get a new description and decide which renderings need to be updated.
  • This model makes “Extract Subview” a low-cost reconstruction, splitting the list cell intoSandwichCellBased on this premise.

@StateLet state be the source of truth

(19:52) The details page needs to switch the image between “fit” and “fill”. SwiftUI’s approach is to declare a state variablezoomed, let againaspectRatioofcontentModeDerived from this state. The click gesture only modifies the state, and the interface refresh is completed by the framework.

struct SandwichDetail: View {
    let sandwich: Sandwich
    @State private var zoomed = false

    var body: some View {
        Image(sandwich.imageName)
            .resizable()
            .aspectRatio(contentMode: zoomed ? .fill : .fit)
            .onTapGesture { zoomed.toggle() }
    }
}

Key points:

  • @State private var zoomed = falseIt is the source of truth owned by this View itself. -contentModeis a derived value, which is given byzoomedDecide. -.onTapGestureJust callzoomed.toggle(), does not directly operate the picture object.
  • SwiftUI observedbodyreadzoomed,sozoomedWill request again after changebody.
  • This explains what is said in session: “Every possible UI state comes from authoritative data”.

Animations and conditional views are still data driven

(31:31) After the picture was zoomed, the demo was addedignoresSafeAreawithAnimationLabelSpacer, conditional rendering and.transition(.move(edge: .bottom)). The focus is not on a certain control, but on the same rule: changing the state, SwiftUI inserts, removes or moves Views according to the new state.

Image(sandwich.imageName)
    .resizable()
    .aspectRatio(contentMode: zoomed ? .fill : .fit)
    .ignoresSafeArea(edges: .bottom)
    .onTapGesture {
        withAnimation {
            zoomed.toggle()
        }
    }

Key points:

  • .ignoresSafeArea(edges: .bottom)Corresponds to the steps in the demo to expand the image beyond the bottom safe area. -withAnimationWrap state changes, animations and final states together.
  • If the user clicks again during the animation, the new state is stillzoomedAs a result, the framework will reverse or continue the animation.
  • When hiding the spicy banner later, the conditional judgment only checkssandwich.isSpicyandzoomed, no need to manually insert and delete the life cycle of the view.

For App-level dataObservableObjectAccess

(42:55) Lists were originally driven by static arrays. In order to support adding, deleting and sorting, session upgrades data to a mutable store: store conforms toObservableObject, will changesandwichesmarked as@Published. For App entrance@StateObjectHave a store, used for list view@ObservedObjectObserve it.

final class SandwichStore: ObservableObject {
    @Published var sandwiches: [Sandwich] = []
}

@main
struct SandwichesApp: App {
    @StateObject private var store = SandwichStore()

    var body: some Scene {
        WindowGroup {
            SandwichList(store: store)
        }
    }
}

struct SandwichList: View {
    @ObservedObject var store: SandwichStore

    var body: some View {
        List {
            ForEach(store.sandwiches) { sandwich in
                SandwichCell(sandwich: sandwich)
            }
            .onMove(perform: moveSandwiches)
            .onDelete(perform: deleteSandwiches)
        }
    }
}

Key points:

  • ObservableObjectAllows model objects to notify SwiftUI that data is about to change. -@PublishedMark the properties that need to be observed and use them to wrap the sandwich array in the session. -@StateObjectPlace it at the App entrance, suitable for having an App-level store. -@ObservedObjectPutting it in the list view means that this view uses the external store. -ForEachrelySandwichconform toIdentifiable, so that SwiftUI can synthesize correct list updates when inserting, deleting, or moving.

The preview is also SwiftUI code

(49:36) The end shows the value of previews. Developers can make a copy of the preview and increase the Dynamic Type; make another copy to set the dark mode; and then set the right-to-left layout and Arabic locale. What Xcode adds is still SwiftUI decorators.

SandwichList(store: .test)
    .environment(\.sizeCategory, .accessibilityExtraExtraExtraLarge)

SandwichList(store: .test)
    .environment(\.colorScheme, .dark)

SandwichList(store: .test)
    .environment(\.layoutDirection, .rightToLeft)
    .environment(\.locale, Locale(identifier: "ar"))

Key points:

  • .environmentInject contextual information into the entire View hierarchy.
  • Dynamic Type, dark mode, layout direction and locale can be individually overridden in the preview. -TextWhen using a string literal, SwiftUI treats it as localizable text by default.
  • The string values ​​in the model will be displayed according to their original values, which is suitable for content such as titles and names from the data source.
  • The session finally emphasized that many behaviors of the entire Sandwiches App are verified in the preview without a full build-and-run first.

Core Takeaways

1. Make a previewable details page zoom interaction. What to do: Add click-to-zoom and exit-zoom to the image details page. Why it’s worth doing: session is already used@StateaspectRatioandwithAnimationShow that this type of interaction can revolve around just one Boolean state. How to start: First make the picture details page independentView,statement@State private var zoomed = false, let againcontentModeand whether the banner is displayed depends on thezoomedderived.

2. Make a cross-platform checklist App prototype. What it does: Use the same SwiftUI list and detail pages to run on iPhone, iPad and macOS. Why it’s worth doing: In the demoNavigationViewIt’s push on iPhone, and it can be turned into columns on iPad and macOS. How to start: Create a project with a multi-platform template, put the shared model in the shared group, use the list as the first column, and then giveNavigationViewAdd placeholder details view.

3. Make an editable data list. What to do: Let users add, delete, and rearrange items. Why it’s worth doing: session useObservableObject@PublishedForEachonMoveandonDeleteThe complete data flow is demonstrated. How to start: First make the model conform toIdentifiable, and then put the array into the store, which is used by the App entrance@StateObjectheld, list passed@ObservedObjectRead and call the modify method.

4. Make a set of extreme environment previews. What to do: Cover large font size, dark mode, right-to-left layout and target language in the same preview. Why it’s worth doing: The closing demonstration shows that these system behaviors can be quickly verified in canvas. How to start: Create multiple previews for key pages and add them separately.environment(\.sizeCategory, ...).environment(\.colorScheme, .dark).environment(\.layoutDirection, .rightToLeft)and.environment(\.locale, ...)

5. Do component-level refactoring exercises. What to do: Split the large list cell, detail header, and bottom status banner into independent views. Why it’s worth doing: Session explicitly states that SwiftUI View is very lightweight, and there is almost no runtime burden in extracting subviews. How to start: Use Xcode’s “Extract Subview” to extractSandwichCell, then use the input attribute to receive the model, leaving the state in the parent or current View that actually owns it.

Comments

GitHub Issues · utterances