Skip to Content
Course content

90: Declarative UI Concepts in SwiftUI

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're ordering a custom pizza. If you were using an imperative approach, you'd have to walk into the kitchen and give the chef a step-by-step manual: "First, roll out 12 inches of dough. Now, spread two tablespoons of tomato sauce in a circular motion. Next, sprinkle 100g of mozzarella. Finally, place twelve pepperonis evenly across the top." If you suddenly decided you wanted mushrooms instead of pepperoni, you'd have to tell the chef to pick off the pepperoni and then add the mushrooms. It's tedious, and there are a lot of places to mess up the sequence.

A declarative approach is much simpler. You just hand the chef a ticket that says: "Large Pepperoni Pizza." You've described the end state you want. You don't care how the chef rolls the dough or which spoon they use for the sauce; you just care that the result matches your description. If you want mushrooms, you just change the ticket to "Large Mushroom Pizza," and the chef handles the transition to make that a reality.

The Shift from "How" to "What"

For years, iOS development was imperative (think UIKit). We spent our time writing code to manually update the UI: label.text = "Loading...", activityIndicator.startAnimating(), or view.isHidden = true. We were the ones managing the transition from one state to another. If you forgot to hide a view when a network request failed, the user ended up with a broken UI. I've spent countless hours debugging those exact kinds of "state mismatch" bugs.

SwiftUI flips this. Instead of writing a series of commands to change the UI, you write a function that describes what the UI should look like for any given state. The framework then takes a look at your state and "diffs" it—calculating exactly what changed and updating only the parts of the screen that need it.

Connecting State to the Screen

Let's look at a real scenario. Suppose we're building a "Follow" button for a social media profile. In the old way, you'd have to manually change the button's title and color whenever the user tapped it. In SwiftUI, we just describe the button's appearance based on a boolean value.

struct ProfileFollowButton: View {
    // This is our "ticket" or source of truth
    @State private var isFollowing = false

    var body: some View {
        Button(action: {
            // We don't tell the button to change color here.
            // We just change the data.
            isFollowing.toggle()
        }) {
            Text(isFollowing ? "Following" : "Follow")
                .padding()
                .background(isFollowing ? Color.gray : Color.blue)
                .foregroundColor(.white)
                .cornerRadius(8)
        }
    }
}

Notice that inside the Button action, I'm not calling a function like updateButtonUI(). I'm simply toggling a piece of data. Because the body property is a computed property, SwiftUI says, "Oh, isFollowing changed! I need to re-run that description and update the screen."

Letting SwiftUI Do the Heavy Lifting

The magic here is that the UI is a function of the state. Mathematically, it looks like UI = f(state). This removes an entire category of bugs. You no longer have to worry about the button saying "Following" while the database still thinks the user is "Unfollowed" because you forgot to call the update method in one specific edge case.

When you're writing SwiftUI, I want you to stop thinking about "changing the screen" and start thinking about "updating the data." If a view isn't looking the way you expect, don't look for the line of code that changes the color—look for the state variable that controls that color. If the state is correct, the UI will follow.




📋 Practical Task

Build a Task Completion Toggle

Your goal is to create a view for a single To-Do item that demonstrates declarative UI principles. Instead of manually changing the text style, the UI should automatically reflect the "completed" status of the task.

Requirements:

  • Create a TodoItemView that contains a @State boolean called isCompleted.
  • Include a Text view displaying a task name (e.g., "Buy groceries").
  • Include a Button that toggles the isCompleted state.
  • Declarative Logic:
    • When isCompleted is true, the text should have a .strikethrough() modifier and the color should be .gray.
    • When isCompleted is false, the text should be .black (or .primary) with no strikethrough.
    • The button text should switch between "Done" and "Undo".
Rating
0 0

There are no comments for now.

to be the first to leave a comment.