WWDC23 SALE: Save 50% on all my Swift books and bundles! >>

Bindings and forms

Paul Hudson    @twostraws   

Updated for Xcode 14.2

So far we’ve let users browse the menu, add items to an order, then see their total order. What we haven’t done is create a mechanism to confirm that order, so that’s our next job.

While this won’t actually send anything off to a server somewhere, I do at least want to use this opportunity to show off one of SwiftUI’s most impressive features: forms.

Forms are containers like stacks, but they are specifically designed for things like settings screens and user input – anywhere the user might want to make several choices in one place. Forms do a few interesting things as you’ll see, and along the way I’ll be showing you how to use common UI controls like pickers, text fields, segmented controls, and more.

Now I know what you’re thinking: surely text fields are easy? Well, they aren’t hard, but they also don’t work like you’re used to in UIKit.

To get things up and running let’s create a new CheckoutView struct that we’ll present when Place Order is pressed. Press Cmd+N to add a new SwiftUI View called “CheckoutView”, then give it the same @EnvironmentObject property the other views have:

@EnvironmentObject var order: Order

Make sure to also provide that in the preview for the view:

struct CheckoutView_Previews: PreviewProvider {
    static var previews: some View {
        CheckoutView().environmentObject(Order())
    }
}

That’s the easy stuff out of the way, so let’s try something new: let’s show a picker with various payment options, allowing users to choose cash, credit card, or iDine Points.

This requires two new properties. First, we need a property that lists all possible values we want to show in our picker – add this now:

let paymentTypes = ["Cash", "Credit Card", "iDine Points"]

Second, we need a property where SwiftUI can store the value that’s selected in the picker. You see, when our UI changes SwiftUI wants to know about it so that it can update our view – maybe some views that were hidden are now shown, for example. Rather than us asking to watch changes by hand, we instead bind our picker to a property on our struct, so that when the picker changes SwiftUI automatically changes the property too. And, just like environment objects, this will cause SwiftUI to re-invoke our body property so any changes are visible.

We already used @EnvironmentObject for working with data that comes from an external source. Here, though, this data is just for our view, and will be a simple value rather than a dedicated class that conforms to ObservableObject.

SwiftUI gives us a different property wrapper for these simple local values: @State. It works similarly to @EnvironmentObject in that if the object changes it automatically refreshes our UI, but it’s designed for simple local values like integers and strings – if you want to use classes like Order you need to use something else instead.

Important: If you want to use simple values that are used only by the current view you should use @State for your property wrapper. Apple also recommends you mark those properties as private to reiterate that they aren’t designed for external access.

Add this property to CheckoutView now:

@State private var paymentType = "Cash"

Now let’s fill in the body property with a picker. This is all new, so I’ll give you the code first then go over what it does:

VStack {
    Section {
        Picker("How do you want to pay?", selection: $paymentType) {
            ForEach(paymentTypes, id: \.self) {
                Text($0)
            }
        }
    }
}
.navigationTitle("Payment")
.navigationBarTitleDisplayMode(.inline)

Xcode showing the SwiftUI code required to generate a wheel picker for iOS, with a preview showing the results.

Let’s break that down:

  1. We have a vertical stack containing one section.
  2. That section contains a picker, which uses $paymentType for its selection.
  3. It has a label that won’t be visible yet, but that will change in a moment.
  4. Inside the picker we loop over all the payment types and add them as an option.
  5. The screen has the title “Payment” in small text rather than a large title.

Of course, the real question is: why $paymentType and not paymentType?

Further reading

Save 50% in my WWDC23 sale.

SAVE 50% To celebrate WWDC23, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Similar solutions…

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.3/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.