View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • AI & Machine Learning
    • App Intents
    • Apple Intelligence
    • Games
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Videos

Open Menu Close Menu
  • Collections
  • All Videos
  • About
  • About
  • Transcript
  • SwiftUI foundations: Build great apps with SwiftUI

    Learn to build great apps with SwiftUI in this special all-day activity streaming from the Apple Developer Center Cupertino. Whether you're just starting out or have experience creating with SwiftUI, this series of foundational sessions will help you sharpen your understanding of core concepts and write strong, performant code. Learn from James Graham, CTO of AllTrails, about how his company took advantage of SwiftUI's capabilities. And dive deeper in a Q&A with members of the SwiftUI engineering team.

    Resources

      • HD Video
      • SD Video
  • Search this video…

    Hello Yay! I know, fun.

    Hi, and welcome to the Apple Developer Center in Cupertino. My name is Leah Womelsdorf and I'm a technology evangelist.

    Today we're excited to share the foundations of SwiftUI and there's a lot to cover. But first I want to share more about our venue.

    The developer Center is part of Apple Park and it's a great venue for today's event. It has different areas for connection and collaboration.

    This room is Big Sur and it's a beautiful space with a great setup. It's designed to support a range of activities including in-person presentations, studio recordings, and live broadcasts.

    There are also labs, briefing rooms, and conference rooms that allow us to host activities like this and many more.

    This is one of four developer centers around the world where we host designers and developers for sessions, labs, and workshops. Has anyone here already been to a developer center? Nice. Welcome back. Whether you're new or returning, we're so happy to welcome you today.

    We also have many people joining us online right now. Hello. Thanks for tuning in. Our developer relations team loves connecting with developers to make the best apps for Apple platforms.

    Since WWDC, we've hosted over 300 activities including labs, workshops, and presentations.

    Later this week here in Cupertino, my team is leading a workshop on the new design. Developers will get hands on experience with Liquid Glass as they update their code and designs.

    To learn more about upcoming events near you, check out developer.apple.com/events. Before I get started with today's agenda, I want to share some tips for people in the room to stay connected throughout the day. Use the Apple Wi-Fi network and if you need to recharge at any point, there's power available at every seat. It's in front of the armrests for everyone tuning in today. These presentations are meant to be a special experience just for you, both online and in person. So please refrain from recording video or live streaming during the presentations.

    On the other hand, photos are totally welcome, so take as many as you like.

    After the event, we'll send out some follow up information with resources to check out so you won't miss a thing.

    With that small request out of the way, I'm excited to share more about today's event.

    SwiftUI is Apple's declarative user interface framework.

    Like any tool, SwiftUI has foundational concepts.

    Taking the time to learn these concepts will empower you to use it well and build something incredible.

    With SwiftUI. The end result isn't just an app, it's an app that can thrive on all Apple hardware. It's intuitive and familiar, even for people using it the first time.

    SwiftUI apps are able to stay modern with the latest updates to the operating system. Like Liquid Glass, SwiftUI is used widely within Apple both as the basis for new apps and the evolution of existing apps that started out with UIKit.

    It was built with incremental adoption top of mind, so you can use it in your code base gradually.

    now more than ever, it's important to take the time to learn the foundations of SwiftUI.

    There are so many ways to write code, whether line by line or using LLMs and agents. Understanding the foundations will enable you to understand and have more confidence in your code.

    Our team has been working on a new app, Wishlist, that's made 100% with SwiftUI.

    Wishlist is the basis for all of today's presentations to demonstrate how the foundations of SwiftUI come together to make a real app.

    My teammates and I love to travel, and I have so much fun planning my next vacation.

    I like to plan them out in depth so I can squeeze the most out of a trip, not just the places I'll go, but the things that I'll do there.

    Wishlist is a travel bucket list app.

    We built this app to track the places we want to go, the activities we want to do, and reflect on our progress as we hold ourselves accountable to dream big and try new things.

    There are two main types of data in the app trips and activities.

    Trips are the locations I want to travel to like Kona in Hawaii, and activities are the things I want to do on my trips, like go snorkeling and whale watching.

    There are three main things to do in the app. By tapping the plus button in the toolbar, I can plan a new trip by adding a title, a photo, and the time of year.

    While I'm on a trip, I can check activities off of my list, like snorkeling with the manta rays.

    I can also reflect on my progress. For instance, this fall I took a trip to Montana and I earned the Fall Explorer badge to navigate through these experiences. Wishlist uses a Tab View.

    We chose a Tab View for consistent navigation. My colleague Majo will explain some of these decisions in her design presentation.

    There are three tabs in Wishlist in the Wishlist tab. I can scroll down to browse all of the trips I have planned or add new ones.

    When I tap on a card like Kona Deep Dive, I'm taken to the Trip Details page where I can check things off.

    The goals tab is where I check my progress towards awards. In the top row I see the awards I've recently won like Fall Explorer.

    When I scroll down, I could see my progress toward my next milestones. I've already checked off seven activities, so I'm just three away from earning the ten activities award.

    The third tab is the search tab.

    I use search to quickly find what I'm looking for. Once I've already added a bunch of trips. It's really helpful to search and dive into the exact one that I want.

    My colleagues will tell you more about how we built the app, but perhaps more importantly, the foundational concepts to make each decision.

    These foundations are the most important thing to take with you today. Apply this theory to your own code so that you can reason about it with confidence.

    Wishlist was a lot of fun to make. At every step, from ideation to design and actually building it out in this app sets the scene for the rest of today's presentations. In the coming weeks, we'll have the sample code for Wishlist available to download from our website. And I'm so excited about this. It's a great way to follow along and cement your learning along the way. If you have questions about the examples or SwiftUI in general, you can use Slido to ask questions to Apple engineers.

    Our team is eager and ready to support you, and you can ask questions about the examples or any SwiftUI question.

    You can also upvote questions from other developers and read the answers. It's a great resource for learning, so I encourage you to check it out.

    All right. Now it's time to dive into the agenda for.

    Today's presentations cover foundational topics of SwiftUI.

    And this is really important. Foundations are useful whether you're just starting out or you already have experience and want to sharpen your understanding of the framework.

    Even if you're already familiar with SwiftUI, developing a deeper understanding of the foundations will help you choose better implementation strategies and solve problems in their in your apps.

    I'll kick things off with an overview of SwiftUI.

    After Majo will share how SwiftUI empowers you to design with the system.

    Then we'll take a quick break and reconvene at 1115 Pacific.

    Then Cat will guide you through the layout system in SwiftUI.

    Curt will follow that up with SwiftUI in motion covering techniques for animation and visual effects.

    Then we'll take a break for lunch to grab some refreshments and reset. We'll meet back here at 130 Pacific, when Cole will demonstrate how to model your intention. Model your data with intention in SwiftUI.

    And then we have a special guest. James. Graham. The CTO of AllTrails will share key learnings about their journey incrementally adopting SwiftUI from a complex, mature UIKit app.

    We'll take one more break to stretch and grab some coffee, and then end the day with a panel of leaders in SwiftUI engineering. They'll answer some of the most popular questions from today, and share their vision for the framework for people here in Cupertino. After that, we'll have a mixer with some light refreshments and an opportunity to connect with Apple engineers and designers.

    All right, now I'll kick things off with my presentation on SwiftUI Essentials.

    I'm Leah and I'm a technology evangelist. Before I joined the Evangelism team, I was an engineer here at Apple.

    I worked on some of my favorite apps the fitness app, the workout app, and the health app, and I even had a brief cameo in the 2021 Keynote. This is pretty cool, right? It was super fun to film. I got to run around Apple Park.

    I started in Apple in 2019, the same year that SwiftUI was announced.

    Over the years, I've learned a lot about the framework, how to use it, but more importantly, how to use it well.

    When I first started using SwiftUI, I loved how quickly I could prototype and build real functional features in an app with a few lines of code, I could make something real. And that was awesome.

    This is something that many software engineers go through, regardless of the tool or the framework. It's super exciting to get something on screen, but sometimes it doesn't always work like you expect. So I needed to take a step back and start with the basics.

    I needed to understand how SwiftUI works so I could make better quality software.

    Today I'll share concepts that are central to how SwiftUI works.

    These concepts will help you write better code, and they'll also set the scene for the rest of today's presentations.

    I'll start by taking a closer look at a term used a lot in SwiftUI view.

    Then I'll cover the views that are built into SwiftUI and the logic behind making new custom views.

    Finally, I'll cover dependencies and how to structure your code with intention.

    In each section, I'll share the most important concepts for each and how they relate to the bigger picture of writing. Great SwiftUI code.

    All right. In SwiftUI, the term view is an overloaded term.

    Depending on the context, it can mean three different things. And this can be a little confusing.

    In many frameworks, view refers to the user interface and pixels on the screen.

    In SwiftUI, a view is also a protocol. It's a description for what you want on the screen.

    Because each view is a struct, each instance of a view has a particular value.

    These three concepts are all related. The pixels on the screen are a result of the description of the view, and the actual values of that particular view struct.

    The description of the view and the values that drive it result in the final pixels on the screen.

    These three meanings of view come up in different areas of an app.

    The description is the code itself.

    The value is the instance in memory. So SwiftUI can render the pixels, and the pixels on the screen need to show the latest, most accurate information.

    I'll go into each of these different meanings of view throughout my presentation.

    The context is important and it will help you think through problems in your own SwiftUI code.

    I'll start off with views as descriptions.

    In SwiftUI, views are descriptions with intentional ways to build them.

    Let's say I want an image of a cool underwater scene with snorkeling in English. To describe this, I'd write the phrase image of snorkeling underwater.

    In SwiftUI, I build this description with the view protocol.

    Image is a SwiftUI view, and Deep Sea is the name of an image, just like my phrase in English. Views. Describe what I want in SwiftUI.

    SwiftUI takes the view and decides what to render on the screen like this. Nice photo.

    All SwiftUI views are descriptions that are written with code.

    This is true whether they're built in views or custom views that you write yourself.

    Image is an example of a built in SwiftUI view.

    Views are the building blocks of every app, and the built in views are a great way to get started. There are many built in views in SwiftUI, and each one's name describes what it produces.

    For instance, similar to how image visualizes an image, color is a view that fills the entire frame with a particular color, like purple.

    Built in views are powerful because SwiftUI integrates them with the hardware.

    Here, this purple is actually a context dependent purple color.

    The actual color values adjust based on the context of the device, like if the phone is in light or dark mode, or whether the sun is shining bright on the screen.

    Text visualizes strings like Kona Deep Dive.

    Like color, text views are optimized for the context of where they exist.

    SwiftUI draws the string using a font that's appropriate for the current platform. For larger displays like an iMac, the text view is going to be physically larger than smaller ones, like on an Apple Watch.

    Text views also support Dynamic Type, which is an accessibility feature.

    Dynamic Type lets people adjust the size of visible text on their devices so they can comfortably read it.

    Here, the phone on the right has a larger system font size.

    The text views in my SwiftUI code automatically scale so that the content is still readable, and this doesn't require any additional code on my end.

    For each view, image, color, and text, the view's name is a description of what I want, combined with the values of Deep Sea, purple, and Kona Deep Dive. They result in pixels on the screen.

    Built in views are a great starting point because they're not just useful as is, they're also customizable.

    Customizing views lets you express the unique personality of your app while leveraging the benefits of Swiftui's built in views.

    There are several ways to customize views in SwiftUI.

    My TextView from before looks all right, but I can make it more memorable.

    View modifiers are a tool to customize individual views. I'll dive into some code.

    There are many ways to customize text views. For instance, changing the size or the color of the font. That's something we did a lot in the Wishlist app. For now, I'll start with something simple. I want my text view to visually pop against a bright color.

    The background modifier sets the background of my view. You can provide any view as a background. I chose the color orange.

    Background is an example of a view modifier.

    A view modifier is a method that's called on a particular view like text, and it returns a new view that contains the original.

    The original text view is wrapped in changes from the view modifier, and it produces a new view.

    I like to think of view modifiers as wrappers that surround views.

    Together. These two lines of code produce the original string Kona Deep Dive with an orange background.

    It's a slightly modified version of the original text view.

    You can apply multiple view modifiers to create a compounded custom effect.

    Padding is another view modifier. It adds points to the edges of the view that it's applied to. In this case, padding adds points on all four sides of the text view, and then the orange background fills it in just like background padding wraps everything before it. So all three of these lines of code represents one big view in the view hierarchy.

    One final note on view modifiers. The order is important. Each view modifier only affects the lines of code above it.

    If I swap the order so that background goes first. The color orange only covers the original text view.

    The padding shown with the gray dotted box is applied to the rest.

    Be intentional about the order of your view modifiers. If your code isn't behaving the way you expect, check to confirm that your view is wrapped in an order that makes sense.

    While Viewmodifiers customize individual views, composition is a technique to combine multiple views.

    You can build your own custom views by combining existing ones.

    Let's say I want to build one of these rows in the search tab of Wishlist for Kona Deep Dive.

    I can use some of my built in views from before.

    First, I'll define my view SearchRow.

    It's a struct and it conforms to the view protocol.

    Then I'll add the body of my view. This is something that's required for all views.

    And I'll add an image view of the Deep Sea and my TextView that says Kona Deep Dive.

    By default, SwiftUI stacks them vertically.

    I want them to be side by side, so I'll add a horizontal stack or an H stack like image and text. HStack is a view, but instead of describing what to render like an image, it describes how to render it SwiftUI stacks. Arrange all of the subviews like image and text in a horizontal line.

    Later today, Cat will go deeper into the tools and techniques for layout and SwiftUI. I want to call something out even as I make more sophisticated views. The core concept is the same.

    My SearchRow is a description of what I want, and SwiftUI takes that description to render the pixels on the screen.

    Composition makes code easier to read, and once I've built my SearchRow, I can use it in other areas of my app with just a single line of code.

    In my search view, instead of needing three stacks, three images, and three text views. I just used three of the composite SearchRow views, and later on, if I want to change anything in the SearchRow like make the background purple, I can do it local to that view.

    This reduces the amount of code I need to write, and makes it easier to read and reason about.

    Because views are structs. They're lightweight, so splitting up a view into smaller views like this doesn't hurt performance.

    Just like builtin views, custom views are a description of our descriptions of what SwiftUI should draw on screen.

    The names like SearchItemView are important, but even more so are the views inside of body and the order that they're listed in. SwiftUI uses the descriptions in your code to draw the pixels on the screen.

    Now I want to take this one step further.

    My SearchRow is pretty close to the intended design, but it's not quite there.

    Right now I have three instances of Kona Deep Dive and I don't know about you, but I like to switch up my vacations every year.

    Apps are dynamic and represent data that changes.

    I need a way to switch this up so I can show the other trips on my bucket list.

    This brings me to my last topic. Dependencies.

    SwiftUI views are driven by data. Whether that data stays the same, like my image of the deep sea and the string Kona Deep Dive or that data changes.

    All of the views I've shown today are dependent on data.

    The pixels on the screen are partially a result of the description like image and partially of the data like Deep Sea.

    I mentioned earlier that all views are structs, and that means that all views are value types, and every instance of a view has a value.

    I like to visualize an instance of a view like this with the name of the view on top, like image and the data like Deep Sea below.

    SwiftUI takes a particular instance of a view, including the data to render the pixels on the screen.

    Once the pixels are rendered, SwiftUI discards the instance. It doesn't need it anymore.

    This is the third meaning of view. A view as a value.

    Instances of a view. The particular values power the pixels on the screen.

    Each view instance exists transiently. They're short lived. They're created when they're needed living in SwiftUI memory. And then once the pixels are rendered, the view's job is done and the instance is discarded.

    Note that discarding them isn't a bad or a high stakes thing. Views are lightweight and easy to create.

    I like to think of views as templates, able to stamp out the same thing, creating pixels on the screen. Many times these templates represent data that can be flexible and dynamic.

    For instance, in my app, I've been focusing on the deep sea, but I also need another image of Kyoto.

    This is another instance of a view, but this one has a slightly different value. The name of the image Kyoto is different from deep sea.

    SwiftUI takes these image views which have different values because of the image names, and it produces different images.

    Now I'll take this flexibility and revisit the code for my SearchRow.

    Now, instead of hard coding the name of the image and the text, my SearchRow takes arguments for the name of the image and the title of the Trip.

    This version of my SearchRow is more flexible. I can still use it to make the Kona Deep Dive row, but I can use it for other trips too.

    This gets me closer to the real design.

    When I use the new SearchRow in my search view, I provide all of the different images and Trip names like Mammoth Blush and Kyoto Mystique.

    And this is much better.

    The data is driving the pixels on the screen, and I'm still able to leverage the clean code from composition.

    Keep in mind that this implementation of the search view is still a simplification of the final version in Wishlist.

    The actual search looks up the data dynamically and then populates the search rows based on the images and strings entered in the search field.

    I want to highlight one more thing about these search rows.

    Just like the image views from before, each instance of the SearchRow has a different value based on the Trip name and the photo name.

    SwiftUI can easily compare these and notice they're not equal.

    After SwiftUI draws the pixels on the screen, it releases the instances of the views. It doesn't need them anymore because the pixels are rendered.

    Now I want to talk a little bit more about how SwiftUI works with dependencies.

    For my SearchRow, the description is my view code.

    Different values of the view result in different pixels on the screen.

    SwiftUI tracks important values with dependencies, and by important values I mean the kind of values that could make the pixels seem right or wrong based on the data.

    Here's how it works.

    The first time that SwiftUI runs body, it keeps track of all of the values it reads with a graph.

    The first part of this graph is a node for SearchRow.

    In body. SwiftUI reads the value of photo name for the image view.

    So it adds a node for photo name and an arrow that points down to SearchRow.

    SwiftUI also reads the value of Trip name, so it adds a node and an arrow for Trip name to SwiftUI tracks this because for the pixels to be correct, they need to represent the right photo name and the right Trip name.

    If either of those change. For instance, if I provide a new photo name with. I'm representing with this red dot, then the pixels for the SearchRow would be out of date and SwiftUI would need to draw new ones.

    Dependencies are like the inputs of a view.

    Dependency tracking is one of the reasons that SwiftUI is so efficient at making updates.

    In an app with a lot of views and a lot of data. It would be extremely inefficient if every time one thing changed, SwiftUI needed to redraw everything.

    Data changes frequently in apps and this would cause a lot of unnecessary updates.

    Instead, SwiftUI tracks dependencies.

    I'm representing it here with arrows, and they indicate which views depend on certain pieces of data.

    With this system, when one thing changes, SwiftUI only recomputes and redraws the things downstream.

    Dependency tracking keeps SwiftUI efficient as things change quickly and often in your apps.

    This is sophisticated and there's great news. You do not have to build this graph yourself.

    SwiftUI builds it for you automatically in its dependency graph.

    It keeps track of the properties that each view reads every time it runs body.

    This system keeps the graph continuously up to date.

    Even though you don't have to build or maintain this graph. There are still some things for you to keep in mind for your code.

    Keep views light when building your views, consider what information you've told SwiftUI that you need in body, and whether changes to those views should invalidate the entire view.

    It's best to keep your views light with minimal dependencies, so SwiftUI only redraws them when it's important.

    This doesn't mean that you can't have complex views.

    It means that you should break those complex views down into smaller, simpler pieces like I did earlier with the rows in my search view.

    Use the right tools to represent your data and how to communicate changes only when they should change the pixels on the screen.

    There are a few different ways that a view can depend on data. One way is to pass that data directly into a view, like I did earlier, by providing the specific names of images and trips.

    Another way to create a piece of data is with at state.

    My colleague Cole will go more into depth into at state and each of the other options for data flow in his presentation, but I want to cover some of the basics.

    Properties wrapped with at state. Tell SwiftUI to store that piece of information for the entire lifetime of a view.

    That's the entire period of time that the view is in the view hierarchy. I'll demonstrate with a simple example.

    In the search tab of Wishlist, as I start to type in the search bar, the results filter down.

    When I add the letter J, the most recent items are replaced by my trips and activities that include the search string like hike, Joshua Tree, and Cliff jump.

    When I add another letter, the letter O, the results continue to filter down.

    Out of all of the trips and activities that I've added to my app, Joshua Tree is the only item that includes the string j o.

    The state of my app. The string that I've entered into the search field drives the results and the pixels on the screen.

    I'll build a simplified example to demonstrate how at state works.

    This is a simplified version of the search view, which I'm calling Simple Search.

    It has the core functionality of the real search view, but some simplifications in the design.

    There are only two views in the body. I'm using a text field and a text view.

    The text view is just a placeholder that says results here. This is something I do a lot while I'm prototyping. I put placeholders in. I'll eventually replace it with a custom view that shows the search results.

    TextField is another built in SwiftUI view. It's meant for collecting input. When people tap on it, the keyboard opens and it displays the string that I've entered.

    I provide a starting prompt type here, and then tell SwiftUI to store the string that's entered in the variable named Search Value.

    The dollar sign is syntax for a Binding, which is another dataflow tool that Cole will go into later.

    I decorated the property search value with the At state property wrapper.

    This tells SwiftUI to hold on to the value of search value across updates.

    The initial value is an empty string.

    When I tap the text field, the cursor blinks, indicating that I can type.

    As I type the letter J, the value of search value is changed from the empty string to j SwiftUI. Hold on to that value and can update the pixels for SimpleSearch accordingly.

    The same thing happens when I add the letter O to keep filtering down towards Joshua Tree SwiftUI hold on to the value of search string j o so it can make continuous progress across updates.

    At state is the simplest way to model information that should stick around for the entire lifetime of your view.

    For the entire time that I'm in the search tab, my search value will persist so I can keep adding to it.

    If I navigate away from the tab and then I come back later, the value will start from scratch again with an empty string.

    This is just the first step of building the real search view in Wishlist. Next, I'd need to replace my placeholder text view with the trips and activities that match the search value string.

    For now, focus on these aspects of state.

    At state is a property wrapper in SwiftUI.

    When a property is marked with. At state Eight SwiftUI SwiftUI knows that it's a source of truth for my app, and it holds on to that value across updates.

    State remains in memory for the entire lifetime of the view.

    This means that apps can display data that's dynamic and compounding, like the string typed in the text field.

    There are multiple ways to structure dependencies in SwiftUI, and Cole will go into each of them later. For now, I want to emphasize one thing invest the time to learn how these tools work.

    This way, you can ensure that you're modeling your dependencies to work with SwiftUI.

    As I've covered today, views are the building blocks of SwiftUI.

    By understanding more about the different contexts they are used, you can understand not just the framework, but improve the quality of your code.

    For the rest of today's presentations. As you explore different areas of Wishlist, I encourage you to focus on the theory behind these solutions.

    This way, you can apply those learnings to your own apps.

    From my presentation, keep these things in mind.

    Leverage SwiftUI is built in views to create your own custom views. Explore different modifiers to express what's unique about your app.

    As you build those views or you revisit existing ones, remember to keep the views lightweight. Consider what data each view should really depend on and break complex views down into simpler, smaller pieces.

    Finally, invest the time to learn about SwiftUI.

    By keeping these foundations in mind, you'll be better equipped to reason about challenges as they come up. Thank you so much for joining me. Now I'm excited to hand it off to my colleague Majo. She'll tell you more about how she designed Wishlist with the system. Please join me in welcoming Majo to the stage.

    Hi everyone. Thank you for coming. Oh. So sorry. In the control. Can we put the presenter notes bigger, I cannot read.

    Thank you all for coming with the entire team. We designed Wishlist just for you and this event, and we are very excited to share with you how that process came to life. So hopefully you can transfer a little bit of, you know, my learnings and my design process throughout the years into your own. So let's begin. I'll start with app navigation, which starts with creating concrete sections for your content and your functionalities. That's kind of how I like to start. We need to start planning, you know, with knowing what exactly we're building. So navigation is, you know, kind of like a dry topic, but I personally love it. So we're going to kick off with that. Next, I'll go into layout and talk about finding the best way to present content in the screen.

    And finally I'll dive into visual design. This is our components and visual elements come together to bring clarity and personality to your app.

    Okay, so as I mentioned, I designed this app from scratch and the very first thing I did was thinking about the app navigation, deciding the content and the features that the app will have will give me a good structure. So you can build with clarity, and you'll know how to use navigation Components like the top bar and the toolbar.

    I started by brainstorming and listing out everything my team and I wanted the app to have and do.

    We wanted to celebrate goals and all ideas were welcome. We were on this brainstorming stage.

    The designer said only for a minute. From there, I simplified and I kept only the essentials for a travel bucket list app like create trips, add photos, search, and then I step back and group related ideas together like trips and activities and progress and celebrate completed trips.

    These groups represent the top three sections of the app, so I named them Wishlist Goals and search.

    Now this is our app. This is what it means to you.

    Whether you're starting from scratch or revisiting an existing app. It is incredibly helpful to go through this exercise. I've done it with developers here in the Developer Center for for a while in workshops, and it's always very eye opening. So I encourage you to do the same. So it helps you organize your thoughts and turn all these loose ideas that you have in the brainstorming into connected screens that now you will be ready to build.

    I'll explain how all of this connects to SwiftUI. I know that this is what you're here for. I'm getting there in iOS. There are two components that support app navigation. The top bar and the toolbar.

    First, I'll show you how the top bar works.

    The top bar shows the top level sections of the app and it remains visible across all screens.

    In this example, the app can feel more complex than what it actually is. We all see in these apps where, you know, the more features I have, the more things. The top bar keeps bugging us, but not a lot of people likes that. It gets very complex. So one thing I always recommend is keeping the number of tabs low.

    It helps you to stay simple and it's very predictable. It reduces decision making. So whenever I open the app I know exactly what options are available to me.

    Second, keep your tab bar native. Is this in your bingo card for today? So SwiftUI components, as you know, like the tab bar come with built in behaviors like animations and accessibility support. So these kind of behaviors can easily get lost if we customize.

    But don't worry, there will be plenty of other places in your app where you can express personality. The top bar is just not one of them.

    Finally, make sure the top bar uses clear symbols and labels that match what is inside each tab.

    Wishlist doesn't have a universal symbol, right? So I chose a rainbow, which is still recognizable and captures trips people aspire to take, right? Like it's hopeful.

    The goal is to have, on the other hand, uses a symbol that is more explicit, it's more explicit, and matches its label very well and has the same shape as many of the collectibles inside, which I thought it was a nice touch.

    Your tab bar can be just as effective as efficient if you follow some of these guidelines.

    Now I'm going to take a quick detour. If you want to dig a little bit more into design or tab bars, visit the Human Interface Guidelines. You have heard that from us before. The Hague is the home for design guidance and best practices across all Apple platforms and technologies.

    This is your first stop for questions and advice before you come to us, and you can finally find a link for The Hague in the design section of the developer website, which also contains the incredibly valuable Apple design resources.

    The designs for the Wishlist app and almost every other app I've designed in my life use native components from this library.

    And while you're browsing and building your design toolbox by not downloading the SF Symbols app. It's apple cider of iconography. It has seven more than 7000 symbols that you can just copy and paste into your designs or code.

    These are the ones that I use for the top bar, and it won't be the last time. I'll refer to it today. So okay, back to the talk track. Both the top bar and the tool bar support app navigation. But there's a difference, right? They act at different levels. People will use the top bar to move across your app. We said top level navigation right. But when it's time to take action and to go within a particular section, we'll use the toolbar.

    The toolbar has different elements to support navigation. First, the title of the current view. In this screen, you can see that people.

    They can tell that they have. They are in the Wishlist, sorry, in this in the Wishlist section. And they have some context about the content of the screen. Kind of like sets the tone. And then the toolbar shows the control for the most important actions that are on screen.

    Here the primary action is to create a Trip. So I place a control in the top right to do so.

    The third element of the toolbar is navigation controls. Here in the Trip detail, I added the back button that allows people to pop back one level and reach Wishlist again.

    To keep it easy to scan. I minimize the number of actions. Same guidance right as in the top bar, and make sure the meaning is clear by choosing familiar SF Symbols when there are too many items like. Clearly in this example, it's difficult for people to understand what is expected for them to do first. So to fix that, I can simply find the actions that are less common or are there more advanced and hide it behind the more menu.

    Toolbars also offer a prominent style for key actions. It adds a pop of color and creates an instant focal point. When you're designing your app, make sure to use only this style for one action per screen. At tops, I know that there are a lot of prominent features that we might want to highlight, but you know, if everything is important, nothing is important.

    So in this case, what would be a travel bucket list up without any trips. So I want to make that prominent.

    And last thing I'll say about the toolbar, just like with the tab bar, it's best to keep it native. We should say it together.

    Adding extra stuff like a background doesn't really, you know, it competes with your content. It competes with functionality, with morphine effects. And later Curt will talk a little bit about that too.

    So up to this point, I've focused on the structure of the app and how people will move through it. And now it's time to bring content into the screens and decide how we're going to present it.

    This is what I mean with layout.

    I'm going to show you a couple examples of two layout patterns that I like to use lists and collections.

    Both are highly flexible and you're more than welcome to choose one or the other, but you're going to figure it out soon that depending on the content that you want to display and what people need to do with it, there's one option better than the other one.

    So for example, I use list when the content is text based. Yeah. And multiple items that we need to display. And it helps people scan through it very quickly. So that's why this layout works well for Trip activities.

    Here I'm using a style called edge to edge because I need to. And when I need to categorize content, I use a group style. So it's a subtle difference. But the inset, the inset layout and the rounded corners really separate the different categories of content that I could have in a list. So I didn't really needed this style in the app. As you download it and start playing with it, you're not going to find this example, but I wanted to show you how I could do it, because there's always some some confusion around like, when do you use edge to edge or when do you use inset? So this is how we do it.

    Lastly, do you help people move and act quickly through a list? I use accessories and controls. Accessories such as images and subtitles help people recognize items faster without needing to read line by line and controls like the selection button here helps people take action without going into a different view, which is very common. Sometimes apps get really complex because we're adding views for just a couple actions that we could just get done from our list view.

    There are many types of controls that you can add and support different functionalities. So I would encourage you to go and explore what's available to you and see if there's any opportunity to simplify your layout. Here we have steppers, toggles, sliders, and many more for you to try.

    And that covers lists which help people move quickly through text. But when the goal is to browse through photos, videos, or or products, collections are a much better fit, and SwiftUI collections are essentially StackView with a ScrollView that allows content to extend beyond the screen, and it invites people to scroll and discover what's inside.

    But here in the Wishlist tab, the primary goal is to browse. So I choose to build a layout with multiple variations of collections that gives trips a more visual presentation and feels personal and exciting, showcasing photos that people uploaded.

    Now keep in mind that with collections, not all content is visible at once. Most of it is off the screen. So to set the right expectations and encourage people to scroll through them, I'll make sure to add titles and image effectively. What does it mean? Well, in this example, do you think the images add value? Does it look a little bit random? Yes. Yes. Very random. And that's the thing that sometimes we lose credibility in the content because the images doesn't just make sense. It doesn't look curated.

    And then we can add titles that shows that shows consistent length. Otherwise again, the layout does look a little bit clunky and it looks misaligned. So not only it hurts the collection, but also the vertical scroll whenever I have something underneath. Now everything looks like it's a little bit wobbly, so it's nice and clean to try to set some rules for you in the content of your collections.

    Okay, so SwiftUI already handles many design principles that I have been sprinkling a little bit through throughout my explanations, but things like hierarchy, alignment, and proximity, those are all part of the components. But also we encourage you to start exploring those to create your layouts. And that is a big part of visual design.

    So we're going to use text color and again imagery to guide attention and express your personality. So far we've been quite functional trying to be effective. And now let's see if we can bring a little bit more your charm. So I'm going to focus on three aspects of visual design that have the biggest and earliest impact. Textiles, semantic colors and consistency.

    Together, they make the app enjoyable and easier to understand and something that I love. They'll give you guidance to reuse your to reuse patterns as your app grows.

    I'll start with textiles so they style hierarchy. They sorry. They set up hierarchy and encourage readability across different screen sizes and conditions. So I'll use system textiles and you get that hierarchy right out of the box. But what's important is that you choose the right textile for your purpose in the app. I use this consistently. For example, title three is for all section titles like Summer glow. It makes every screen look more balanced and more polished, because there are concrete sections of content. And the moment that I see a textile that I know in which hierarchy represents, I know exactly what the content is going to mean.

    Another reason I rely on system textiles is Dynamic Type. So lots of people use larger textiles because they need it for comfort or sometimes for both. And when you use Dynamic Type, those textiles are named the same, but they are consistently larger. So please use it.

    If you are a font fan, you'll notice that I use Apple System font SF Pro across the entire app, but I've obviously not just using one style. SF Pro includes different variants that let me shape the personality of the app without compromising legibility. We were going for a more sporty type of vibe, so I've been using expanded for emphasis in titles and condense only sparingly in some overlays.

    Here again, I want to keep my choices minimal so both the UI feels intentional and the app is easier to maintain and grow. Then we're going to get back to our textiles and it's like, oh, when do I use expanded? When do I use Kona? And now we have a bunch of textiles, a bunch of variants, and hell, a lot of fonts.

    So earlier when I explained collections, I mentioned that imagery carried a lot of the app's visual weight. So semantic colors are a good complement of the UI, and they have a very similar role, but much more specific, which is status and feedback. For example, I use color Indigo across the app. And here, for example, it's in completed activities and in the selected tab in the top bar.

    I avoid using it or any color that is really similar to Indigo for decoration. Otherwise people might not understand like, is this interactive or is it? Does it have any meaning? I set this color is named indigo. And before that we are in describing semantic colors. So it's not a color that is that is around that is. Yeah, I chose a random.

    I provide it's provided by the system and each color in in the native, sorry, each native component has its has its own color. So I didn't set the background. I didn't set the separator color. All of these are already out of the box for me. The only thing that I chose was this accent color.

    So because these colors automatically adapt to light and dark mode. Also Liquid Glass and different screen environments. It's best not to get overboard again with customization, especially with buttons and controls.

    Probably you've seen in the app that the color palette also includes a neon green, and I reserve it only for emphasis, like in progress indicators and Subheadlines. Again, trying to perceive meaning and these visual metaphors. So the color is not semantic. You're not going to find it in our kit. So I make sure that it has enough contrast. I tested it against like different, different backgrounds. And I also provided a value for increased contrast.

    So if you decided to use a non-system color. Just make sure to follow some simple rules, just as this one. Keep testing and just make sure that your app still is still expressive, but without affecting usability.

    So I'm getting closer to the end here, and that means that it's a good time to make sure everything looks at best. And for my final touch, I'll go back and make sure that all elements are lined up and consistently spaced out.

    This makes the design feel much more polished and visually balanced. It looks professional, and it also supports how people take in information and decide what to do next. If you have a lot of components like cramped in little space, what happens? We feel stressed, like we don't have space to think or time to think. And when we make the UI breathe a little bit more, That's when a great experience started to happen, where giving people space to process.

    So when using native components, I'm careful to use them also in a same way, in the same way across different screens. I avoid giving people multiple ways to do the same thing, which sometimes happens. We get excited creating a new screen and we start from scratch. But the best, the best part of it not only to simplify development, but the, the experience that people are going to have is to repurpose these components. They know how they they know where they seen it before, they know how they behave. And they know exactly what is expected from them. So progress indicators, for example, here use the same accent color and the same shape, but they are a little bit smaller still. They are in a context that I know. Yeah. What, what did they do? And that consistency also helps with your development. You have less components to build.

    I briefly touch on imagery while explaining collections, but there are, of course part of visual design. So when selecting your images and illustrations, place them side by side and look if they are familiar in lining, level of detail and overall mood. Then you can tweak and adjust so they feel like they are part of the same brand. If they feel like they belong in the same collection, follow your gut. They are probably right.

    In Wishlist, for example, people will upload their own photos. But again, to illustrate the point, I've used images to show you how you can also have it in in the code, you're going to have that access to those images. So you can see kind of like the pattern that we went through. So I'm going for dynamic Sky. So often the subject is smaller or interacting with the space, but the idea is that the UI is more prominent than the photos, but definitely something for you to evaluate to get a consistent look in your apps.

    So stepping back, I can really take a lot of credit for the design of the app.

    Maybe a little bit, but SwiftUI is handling a lot of the design decisions for me. And that is like yes and honest thing to say.

    But it's true. I really enjoy working with with the engineers in creating this app, and it's so cool to see that everything that I have designed, it has a very similar translation in code. So we're very excited to share it with you and that you can get to play with it. And hopefully you can take a couple of these tips for, for, for your process and reduce a little bit of uncertainty that, you know, sometimes it happens when you want to get creative, just like at any random point or just give you a space to be creative at the beginning. Make decisions, brainstorm, and then get to code.

    So as you get back to work, define or assess the structure and its navigation. Use components mindfully. This will help you make clear decisions. So at the moment that you start coding, you know exactly where you're going. You're exactly what you're building. And yeah, you'll build an app that is much more intentional. Okay, so partner with SwiftUI, let it do the heavy lifting and then make your best job bringing personality, creativity, and humanity to it. Thank you so much. I hope you have a lot of fun building it and I'm playing with the app and that's everything on the design side. Thank you for coming. And now I'll hand it back to Leah.

    Wow. That was awesome. Majo. I love how SwiftUI system components make it easy to design an app that people quickly know how to use. Wishlist is a beautiful app and taking a moment to pause and appreciate the thought behind each decision makes me value it even more. Whether I'm prototyping something brand new or refining an existing app, I always try to think about opportunities to leverage the system components.

    Well, now we're going to take a quick break. We'll reconvene here at 1115 Pacific for a presentation on layout in SwiftUI. I'll see you then.

    Welcome back.

    I hope you enjoyed the break and had the chance to grab some refreshments or stretch out. Now my colleague Cat will share a guide to layout in SwiftUI. Please join me in welcoming Cat to the stage.

    Good morning. Hi everyone. My name is Cat and I'm a development tools engineer here at Apple.

    Over the past few years, I've worked on projects like the Vitals app for Apple Watch, as well as the sleep experience in the health app on iPhone and iPad. Yeah, these are experiences that need to feel intuitive and look beautiful. Whether you're glancing at your wrist or looking at your phone.

    Through this work, I've learned that strong UI layout fundamentals are the foundation that make this possible Today, I'll cover the principles that are universal building blocks in SwiftUI layout, no matter which platform you're working on.

    First, I'll revisit some conceptual components of SwiftUI that are especially important for layout, followed by SwiftUI layout mechanics.

    Then I'll take you through examples of how to get predictable results using SwiftUI.

    So I'll start with the fundamentals. Views as Leah described this morning, SwiftUI view is a lightweight template describing what will appear on screen.

    A view is a template that represents the position, size, and hierarchy.

    SwiftUI creates lightweight view structs to describe what's on the screen and discards them, making a new struct on following updates.

    SwiftUI update engine only updates changed UI parts, ensuring predictable and efficient results based on state changes.

    This efficiency comes from Swiftui's local update model. Changes in one part of the view hierarchy don't cascade to unrelated subtrees, so only the affected subviews are Rerendered.

    And SwiftUI. The view template controls everything from positioning and sizing to rendering and state updates.

    Now that I've gone over what views are and how Swiftui's update engine works, I'll show the mechanics of how these concepts come together when SwiftUI performs layout.

    As I go over layout mechanics, I'll be focusing on the TripCard I built in the Wishlist app.

    The TripCard provides a great example of how SwiftUI handles dynamic layouts based on different states.

    And SwiftUI layout is a function of the state. When I say state here, it doesn't mean the at state property wrapper, I mean state in general, like the name of a Trip such as Cali Coastal Trails here, or the URL of the trip's image. SwiftUI inherently abstracts state from layout.

    This is possible with other UI frameworks as well, but it requires some effort and discipline. But this abstraction is an integral part of SwiftUI.

    State drives the layout by dynamically controlling the UI.

    state also populates what's inside each of those views, like the strings and images that are being displayed on screen.

    In other frameworks, state changes require manual updates to relay out specific parts of the UI, and SwiftUI state changes automatically regenerate the affected view templates, always ensuring that they stay up to date.

    Now I'll discuss how I built the layout for the Trip cards in the Wishlist app, as shown here to explain how to abstract layout from state.

    The TripCard is shown against a plain dark background.

    It has a VStack containing an image representing the Trip and a text view with the Trip name.

    The Trip image view has an overlay that displays the number of activities, but only if the count of activities is greater than zero. Otherwise, the text is never created and SwiftUI won't render the activities overlay.

    The state of the view is controlled independently by a Trip from the model.

    The Trip model has a name string for the title of the Trip and a photoURL. To determine which image to render for the Trip.

    And lastly, it has a dictionary of activities. The count of activities in the dictionary is used to determine if the activities overlay is displayed.

    This is a simple example of state controlling the SwiftUI layout and how the value. In this example, the number of activities is used to customize the layout of the views.

    Next, I'll explain how layout works in SwiftUI.

    The basic premise of SwiftUI layout is that a container proposes a size to its Subviews.

    The size of this proposal is constrained by the container view and all its previous container views.

    Each Subview responds by calculating and reporting back its preferred size.

    Different views and SwiftUI have different preferred sizes.

    A color view always claims whatever it's offered. It grows to fill the available space.

    Imageview always claims its full size, even if it's offered less space. This means images can spill outside of their containing views.

    Use the resizable modifier to override this. Then it will claim whatever space is offered, just like color, even if it ends up appearing squished like with the coastal flowers here.

    To preserve the images original aspect ratio. Set the content mode to fit or fill.

    Text claims at least enough space to show an ellipsis. Text will claim only the space it needs for its content.

    Layout and SwiftUI happens hierarchically.

    A container view proposes a size to each of its subviews.

    Suppose the proposed size is specific. For example, this orange box shows what a proposal could look like.

    If the container view is the root view of an app. The proposal is the device size or if you apply a frame modifier, the proposal is the size of the frame.

    On the other hand, sometimes the proposed size is unspecified in one or both directions.

    This means that the container view wants to know how much space the Subview would want if it wasn't constrained at all. This is the Subviews ideal size.

    Each Subview responds with its preferred size given the proposed size.

    This is a special and unique behavior of SwiftUI compared to other view systems. Proposals don't just go down, they also go up.

    This layout process is recursive.

    Proposals flow from the root view down the entire view hierarchy.

    Then responses flow back up.

    With the sizes in hand, the root view tells all its subviews where they should draw, they tell their subviews, and so on until all the views are drawn.

    Now I'll take you through the same traversal again. Again, this time with some actual views and actual values in the TripCard here.

    The TripCard appears in a horizontal stack inside a horizontal ScrollView.

    I want all the Trip cards. Kali, Kyoto and others to have the same height, regardless of the size of the source image or the length of the Trip name.

    I can achieve that using fixed height frame.

    SwiftUI offers unlimited width and the fixed height of 220 to the VStack at the root of the TripCard.

    The stack then offers the size to the Trip image view the height of 220. Here is just an example of a fixed height frame.

    The image view responds with the exact size it needs 185 by 150 points.

    The outer stack subtracts the returned height, then offers the remaining space to the text that contains the Trip name.

    The name text replies with the space it needs 15 by 130 points. I've reached the last view.

    Now each view has replied with the size it needs.

    That is each view besides the activities overlay. I'll get back to that one later in the presentation.

    Completing the process. The VStack combines the requested size of the inner image, view and text, and returns the final requested size of the view.

    So that's how SwiftUI layout works.

    To recap, SwiftUI layouts are traversed from top to bottom, and size information is shared back up to the root at any level. The space available is provided by the container view.

    the space needed is determined by the subview, possibly by checking with its own subviews.

    The layout is recomputed only when state changes, the view template is always recreated.

    State controls the content, so when the Trip value changes, the view changes automatically.

    Awesome. It's time to create some stunning SwiftUI views.

    When I was just starting out with SwiftUI, I would build a view and sometimes not get the results I expected. So next I'll share some guidelines to get predictable results by keeping your layouts simple and composable.

    The first consideration for predictable layouts is layout priority layout priority is used to determine the order in which views are laid out for spacing and resizing.

    When there is not enough space to meet the request of the view, more space is given to views with higher layout priority layout priority is set with the layout priority modifier and the default value is zero. The higher the value, the higher the priority. So for example, a priority three view will be higher priority than a priority one view.

    This is probably the opposite of what you're used to in your bug queues, where p1's are the highest priority. But in this case it's the opposite. The higher the number, the higher the priority.

    And the Wishlist app. I created a section of trips where the cards have a wider width.

    I was chatting with our Wishlist app designer Majo, and we think these wide trip cards are the perfect place to take advantage of the extra space and display the trips subtitle and creation date.

    Sometimes with multiple text views in a container view. The text might be truncated or wrapped based on the available space.

    In this example, once I added the subtitle and date the Hawaii United States text on the bottom left hand corner of the card became truncated.

    I might not know how much space is available. For example, it can vary with different sized devices, and I might not know how much space I need. Some trips have longer subtitle strings, so annotating the importance of various text in the layout gives you the power to decide which text to truncate.

    You can do that by increasing the layout priority of the text from the default value of zero to a higher value like one.

    As I shared earlier, the stack offers space to the higher priority views first, so the subtitle gets all the space it needs. But this forces the date text in the bottom right hand corner to truncate.

    I shared this layout problem with our designer Majo. She suggested hiding the creation date when there is not enough space, so the Trip subtitle is fully visible.

    I think that's great advice as it avoids string truncation. Now I'll show how to do that.

    I moved my HStack inside a ViewThatFits view. ViewThatFits evaluates its Subviews. In the order you provide them to the initializer.

    It selects the first Subview whose ideal size fits within the proposed size. This means that you provide views in the order of preference. Usually this order is largest to smallest.

    So I added a text view with just the subtitle. When the views in the HStack would truncate, ViewThatFits will choose the text view.

    I'm sure these changes will make our designer Majo happy.

    Next, our stack alignments. Stacks place their views to have matching alignment. The default alignment is center, but other alignments can be specified.

    In addition to center, the views in an HStack can also be vertically aligned at their tops or bottoms and also on firstTextBaseline or lastTextBaseline.

    The views in a VStack can also be horizontally aligned at their leading edge, trailing edge and others.

    The section header for Trip collections in the Wishlist app is a perfect example. By default, stacks use center alignment to align views, but sometimes when you have a series of elements, this can appear misaligned. In this case, it's best to have them all baseline aligned.

    Here, the subviews of the section subtitle are using the default alignment. That means the show all is floating above the visual line established by the subtitle text.

    By changing the HStack alignment to firstTextBaseline, I bring the show all up to the same visual line established by the subtitle.

    Now I'll share a few more things to consider while building layouts in SwiftUI.

    Wherever possible, create adaptive layouts instead of explicit layouts. Adaptive layouts let you more easily move to different device sizes, window sizes, and platforms.

    Avoid manipulating the view frames explicitly instead of using explicit heights and widths for views. Let them expand to fill the available space.

    Only use view modifiers such as frame or position, when the desired layout can't be implemented in an adaptive, flexible way.

    Similar to Zstack. To add depth to your view, you can use background or overlay modifiers.

    Overlay and background modifiers are not included in the layout sizing and always will have the same size as the view they modify.

    This is why in the layout tree traversal example, earlier the activities overlay was not included in the layout calculations. It inherited the calculated size of its container view. The image view by default.

    Layout issues happen. I still sometimes encounter them. Now I'll share some techniques that I use for identifying and fixing those layout issues.

    Many of these are based on the power of SwiftUI for rapid prototyping. I can make a small tweak and the results will appear immediately.

    One simple technique is to add colored borders like red on the image and blue on the text, as I've done in the TripCard here.

    This technique is especially useful for understanding stack layouts and padding around views.

    Sometimes temporary borders overlap, and I want a stronger representation of the size and position of subviews. In this case, I use overlay modifiers with translucent colors to reveal the full extent of subviews and how they layer.

    It can also be useful to print the value of a property when a view is rendered.

    You might have tried using print and been disappointed by a compiler error.

    Here the error reads build expression is unavailable. This expression does not conform to view.

    This error is because the print expression in Swift has no return value, so its return type is void. And void isn't a view, but the body of a view does support variable declarations.

    I can fix this error by declaring a placeholder variable. Now I can write my print expression on the right hand side of the equals sign. This compiles without error and prints output to the console when running.

    Next up, Xcode previews the preview canvas, and Xcode is a quick way for seeing what view goes with what code. Click the mouse pointer icon at the bottom of the canvas to make the preview selectable.

    Then, when I select code in the editor, the preview highlights the related view, and if I select a view in the preview, Xcode selects the corresponding code in the editor.

    The most powerful tool in my toolbox for debugging layout issues is Xcode's View Debugger. By running my app and stopping it with the view debugger, I can explode all the views, then select individual Subviews to focus on. This technique is particularly effective when I'm mixing SwiftUI with UIKit. Which brings me to an important point.

    SwiftUI is compatible with UIKit layouts as James. Graham from AllTrails will share later. To learn more about it, check out the WWDC 22 video. Use SwiftUI with UIKit.

    Now that I've shared the fundamentals of layout in SwiftUI, it's time to put these concepts into practice.

    The best way to learn is to start building. I got started by picking a view from an app I liked and remaking it in SwiftUI.

    Xcode previews is a great way to quickly try out different layouts and approaches.

    Use simple techniques like print and color overlays to diagnose any layout issues you encounter. You'll be amazed at how quickly you can identify and fix the problem.

    Thanks for joining me today. Now go build something special with SwiftUI and enjoy the rest of the sessions.

    That was awesome. Cat. I love the tip about how to get more experience with layout, trying to recreate an existing view, try things out and build your mental model. Next, my colleague Curt will dive into the details of motion in SwiftUI. Please join me in welcoming Curt to the stage.

    Thanks, Leah.

    Hi, I'm Curt, I'm a technology evangelist on the Worldwide Developer Relations team, and I am so thrilled to be with you today and to welcome all the folks online to. Before joining Developer Relations, I worked as an engineer on SwiftUI where I focused on navigation and API design.

    Today I'll talk about the foundations for introducing motion in your apps using SwiftUI.

    As devices have become more powerful, interfaces have grown more dynamic. This motion makes devices feel more alive and personal when done well. Motion makes apps and platforms easier to understand. It provides context and guides people's attention. Plus, it's just plain fun.

    A lot comes together to make these dynamic interactions. There are transitions where people move from one view to another, like pushing into a view in the settings app, or presenting a sheet of focus options and gestures where people directly interact with the device, like zooming into a map to see more details or swiping between apps.

    And finally, animations where an on screen object moves, grows, or changes visual properties like live activities in the Dynamic Island. These all work together to create a fluid, interactive interface.

    SwiftUI is the best way to incorporate fluid motion in your apps.

    Motion in SwiftUI spans the gamut. At the simplest, you get automatic translation transitions just by using the built in SwiftUI components.

    Level up with state driven animations where you can choose from a menu of modifiers to tell SwiftUI how to animate when particular properties change, or go all in with fully custom animations where you specify exactly what should happen frame by frame.

    Today I'll take you through examples from across this spectrum, so you can choose the right tool to create the dynamic moving experience that's right for your apps.

    Many SwiftUI views provide smooth motion effects automatically. I'll share some examples from the Wishlist app and show how you can tweak these automatic effects to invoke the feeling you want in your apps. Then I'll discuss how you can add state driven animations to your app using SwiftUI modifiers and properties. I'll present the foundations of these animations so you're equipped to choose the right technique for the task at hand. Finally, I'll illustrate the power of custom animations in SwiftUI and point you to some resources for learning more.

    When you use built in views in SwiftUI, you get many motion effects automatically.

    This Wishlist app is a great example of this power NavigationStack push when someone taps a Trip thumbnail. Symbols like check marks acknowledge interactions. Details pop back into thumbnails, sheets animate into view, pop up menus morph out of Liquid Glass buttons. Scroll views automatically accelerate when people swipe and decelerate when they stop swiping, optionally stopping on particular views.

    I'll go through four different SwiftUI views you can use to get these motion effects automatically. Starting with navigation stacks like this one in the Wishlist tab that presents trip details.

    The Wishlist app uses a NavigationStack inside each tab.

    Inside this stack are all these tiles for the various trips. I'll focus on a for each that iterates over all the trips in a collection like my Fal getaways.

    Each of these thumbnails is drawn by a navigation link that provides a destination view, plus a label.

    The label is the part of the interface that a person taps on. When they do that, the destination view is pushed onto the stack. By default, it slides in from the trailing edge.

    when they tap the back button or swipe on the display. The destination view animates away. Now some apps like Music and News, for example, refine these pushes and pops using a technique called zoom transitions.

    There are just three steps to tell a NavigationStack to use a zoom transition.

    First, add a namespace to the view's properties. A namespace is a unique identifier that SwiftUI can use to associate two other pieces of code.

    Second, add the navigation transition modifier to the destination view, passing the zoom parameter a unique ID and the namespace.

    Finally, add the match transition source modifier to the links label.

    Now the Wishlist app uses a zoom transition when I tap on the image for a Trip.

    When I navigate back, the detail view shrinks back into the thumbnail.

    Zoom transitions work great when the destination repeats content that's included in the label, like this beautiful picture from Zion National Park.

    Sometimes the label of the NavigationLink is more detailed, like this one from the search tab in Wishlist.

    It shows a thumbnail photo next to the trip's name. In a case like this, add the matched transition source to a Subview of the links label. Here's how these rows are drawn with a custom view named SearchItemView. It uses an HStack containing the thumbnail and the trip name.

    Here I added the matched transition source modifier to the image thumbnail instead of the whole search item view.

    I passed the namespace in from the surrounding NavigationStack as a property And now when I tap the row, the detail page zooms out of the thumbnail.

    When I pop back, the page zooms back into the thumbnail. I just love this little touch. It's fun, and it draws a person's eye to the row where they started from.

    The second kind of built in view I'll cover today is sheets. I'll talk through the code for a sheet in the Wishlist app. Here's the NavigationStack for the Wishlist tab again with a property is presenting. Add Trip that I'll use to determine if the sheet is showing. Inside the stack is a scroll view with a toolbar modifier attached.

    Inside the toolbar is this plus button.

    With that structure in place, there are just two steps to present a sheet. First, the button in the toolbar sets the isPresentingAddTrip property to true, and second, the sheet modifier specifies what should be shown when isPresentingAddTrip is true.

    The modifier here takes a binding to the property. That's what the dollar sign means. Cole will go into more details on Binding in a bit, but the important point now is that this lets SwiftUI set isPresentingAddTrip back to false when someone dismisses the sheet.

    With these in place, when I tap the button, the sheet slides up from the bottom of the screen. When I tap the close button, it slides back down.

    Just like it did for navigation, I can apply my three step process to convert this to a zoom transition. Two. So first I add a namespace to the view's properties. Second, I add the navigation transition modifier to the sheets content passing the zoom parameter.

    And finally I add the matched transition source modifier to the button label.

    Now, when I tap the button, the sheet morphs out of it.

    When I dismiss the sheet, it morphs back home.

    This motion helps people associate the button with the sheet.

    SwiftUI. ScrollView also provide built in motion effects. ScrollView eyes move when people swipe on them with smooth deceleration and a friendly bounce at the end of the content. Here's the ScrollView for showing the badges I've earned in the Wishlist app. ScrollView takes a Subview showing the content that people can scroll through. Here, that's a stack of the tiles showing all of my badges. Optionally, ScrollView takes a parameter specifying what directions it can scroll in. So horizontal here, for the badges in the Wishlist app, I want the ScrollView to always stop with the badge centered on the screen. With just two steps. I can tell SwiftUI to do this. First, I add the scroll target behavior modifier to tell SwiftUI to stop aligned to a view.

    Then I add the scroll target layout modifier to tell SwiftUI which stack of views I want to participate in this behavior.

    With that in place, now when I swipe on the badges, the ScrollView always stops with a badge centered on the screen.

    Now it would be fun. It would be fun to add some whimsy to these badges as they scroll in and out of the view. Apps like Books and Sports use these sorts of motion effects. They do this with the scroll transition modifier.

    Apply the modifier to the view that you want to transform. Here, that's my achieved goal tile.

    I make the transition interactive, so it responds to manual scrolling and set the direction to horizontal.

    The modifier takes a closure. Defining the transition. SwiftUI passes a proxy for the content plus an animation phase to the closure.

    The phase specifies how far along the transition is minus one for completely scrolled away on the leading edge, zero for completely on screen, and plus one for completely scrolled away on the trailing edge.

    Use the phase to modify the content.

    Here I'm scaling down the goal tile when it moves off screen and applying a 3D rotation along the vertical axis.

    Check it out. Notice how the views seem to wrap at the edges as if they're part of a round carousel? That's good stuff.

    The last kind of built in view I'll cover today is an image view with SF Symbols.

    Like Majo said earlier. SF Symbols is a library of iconography with more than 7000 symbols. There are no duplicates on this screen.

    SF Symbols are designed to integrate seamlessly with San Francisco, the system font on Apple's platforms.

    The SF Symbols app for Mac, available from the Apple Developer website, allows you to explore the library and find the right symbol for your use case. For example, the Wishlist app uses a check mark in its activities list to add the check mark in my own app. I add a SwiftUI image to my code in the SF Symbols app. I control click on the symbol I want, check mark, circle fill, and choose Copy Name.

    Then in Xcode, I paste the name into my image declaration and there's my check mark. SwiftUI provides several different ways to animate SF Symbols. I'll share three examples.

    Use an indefinite effect to indicate an ongoing operation, like waiting for someone to send a reply in a chat. These effects run continuously while active. Some examples are variable, color, scale, and breathe effects.

    To add one of these effects to an SF symbol, use the symbol effect modifier with an Isactive parameter. Whenever this argument value is true, the effect will run.

    Use a discrete effect for indicating an event like a download. Completing. These effects are triggered when the event occurs. Some examples are bounce, pulse, and wiggle.

    To add one of these effects to an SF symbol, use the symbol effect modifier with the value parameter. Whenever this argument value changes, the effect will run.

    Use a contentTransition effect when replacing one symbol with another, such as when adding a check mark to a circle.

    To add one of these effects to an SF symbol. Use the contentTransition modifier with the symbol effect type. The transition will run whenever the chosen symbol changes.

    The SF Symbols app also lets you experiment with animations.

    Here I switch to the Animation Inspector. Select a breathe animation and set it to run. Once I click play to test it. Then I copy the animation configuration using the copy menu.

    Back in Xcode, I paste the modifier with the options I configured in the SF Symbols app.

    And breathe in and out.

    SwiftUI is built in views like stacks, sheets, scroll views, and images give you a variety of built in effects. Automatically add modifiers to refine those effects for your app.

    Next, I'll introduce another kind of animation in SwiftUI state driven animations. I'll explain. Earlier, Leah shared how SwiftUI views map from data to pixels on screen, and Cat showed an example of a view being shown or hidden in the Wishlist layout based on the value of a property in the data model.

    Data that's used this way is called the view's state.

    Here's an example from the Wishlist app. This is a Trip details view with a list of my planned activities at the bottom. Floating over this image is this text that shows what percentage of my activities I've completed, plus a bar that fills in as I complete more of them.

    When I check off an activity, SwiftUI updates the associated state to record that the activity is done. The views that depend on this state automatically update when the state changes.

    For now, all the changes happen instantaneously when I check off an activity. I'll tell SwiftUI to animate this instead. Do that with the with animation function. Here's how. Here's the code for the button that presents. That represents an activity on the Trip details page.

    The action of this button toggles the is completed state of the associated activity.

    I wrap this toggling action in the with animation function. This tells SwiftUI to animate any view updates that happen as a result of the wrapped state changing. Here's the update again. Now when I complete an activity, the percentage text crossfades the bar fills and the Activity color and check mark crossfade.

    To animate these changes I just added with animation, the rest happens automatically.

    The power of with animation is its simplicity. Just wrap a state change in the function and every property of your views that depend on that state and can be animated will be. On the other hand, some parts of your app might need a more precise approach to describe that. I'll focus on just this completion overlay from the Wishlist app.

    In the app, these three views the percent complete text, the bar and the subtitle are embedded in a custom ActivityProgressView.

    I'm going to leave out a few styling modifiers plus the subtitle to focus on the animations. ActivityProgressView takes a completion value property between 0 and 1, describing the percent complete.

    A text view with formatting renders the completion percentage.

    This opacity modifier hides the text when the completion value is zero.

    I use a rounded rectangle for the lime green bar.

    The width of the bar is set by multiplying a constant bar width by the completion value, and again, an opacity modifier hides the view when the completion value is zero.

    Now the design for Wishlist calls for animating the ActivityProgressView wherever it's used. I can use the animation modifier for that.

    By applying the animation modifier to this VStack, I tell SwiftUI to animate these views whenever the passed in completion value changes.

    Here's how that behaves so far. It's exactly the same animation as I got using with animation.

    The animation modifier is an alternative to using with animation. At the point the state changes with. Animation is a good choice when you want some, but not all sources of a state change to trigger an animation.

    On the other hand, use animation modifier when you want a view to always animate regardless of the source of the state. Change both with animation and the animation modifier let you change the timing of an animation, its velocity, acceleration, and bounce. Use this to take more control over the feel of the animation.

    For example, it would add a touch of celebration if the bar bounced a bit when it increased. I can do that by passing bouncy to the animation modifier.

    Here's what that looks like. The green bar oscillates just a bit before settling to its new value.

    I can even add some extra bounce.

    Check out what happens now. The bar has a fun bounce.

    There's. There's something wonky with the text, so I'll run that again and freeze during the animation.

    My extra bouncy animation shoots past the target value, then retreats towards the original before finally settling. And with the numbers, this retreat is far enough that the digits start fading back to their starting values. I can solve this by adding a second animation modifier.

    I add a smooth animation to just the text view.

    Now the bouncy animation applies to the whole VStack, But I override that animation just for the text. Subview.

    Now the glitch with the numbers is gone. The bar bounces, but the numbers crossfade smoothly.

    Now that that's sorted, I'll dial the bar, bounce back a bit, and add one more motion effect to the text.

    The contentTransition modifier with the numeric text argument tells SwiftUI to use a special counter animation when the numbers change. Now the digits roll up in order, calling attention to the change.

    I love that one.

    Summing up, SwiftUI views map from data to pixels. State driven animations let you control the behavior when the pixels update as the result of this data or state changing.

    Specify how those animations should behave by either wrapping the actual state change in the width animation function, or by adding an animation modifier to the views. Now, before moving on, I'll share just a bit about the optional parameter I use to control the bounciness of the bar animation. This optional parameter controls the timing of the animation. Here's what I mean. I use the bouncy animation for the bar. The animation overshoots its destination before easing back. It's the most playful of the built in animations on a plot of value versus time. The value overshoots before settling to its final level.

    On the other hand, the snappy animation moves quickly to its final value, giving a feel of precision and professionalism.

    The plot shows a distinct knee where the value reaches its final level.

    The smooth animation sits at a sweet spot between bouncy and snappy. It settles quickly, but feels more casual than a snappy animation.

    It has a gentler bend and approaches its final level more gradually. Smooth is a great general purpose animation. In fact, it's the default on all of Apple's platforms.

    Finally, use the spring animation to customize all the properties of a spring. This gives you fine grained control. Tune the bounce to control the playfulness of the animation. At a bounce of 0.6, the value oscillates multiple times before finally settling. You can also tune the duration of the spring and even how it interacts with other spring driven animations.

    Typically, one of the named spring's bouncy, snappy, or smooth will be appropriate, but it's nice to know you have control if you need it.

    For more details on how animations and SwiftUI work under the hood, Check out explore SwiftUI animation. Then bounce over to animate with springs for technical and design guidance on animation timing.

    Both videos are from W 23.

    I've shared how the Wishlist app uses Swiftui's built in views to get beautiful motion effects automatically, and how the app uses state driven animations to add an extra touch of polish.

    I'll wrap up with a couple of examples of custom effects built with SwiftUI.

    These examples aren't in the Wishlist app today, but I'll explain how you can add them. Experimenting like this is a great way to get a feel for what's possible in SwiftUI.

    My first example is a bouncing ball. This might work as a loading indicator. Implement this using a PhaseAnimator.

    This animation has four phases. First, the ball drops.

    Then it squishes. That's a technical term.

    The ball expands again and then it rises.

    This cycle repeats. An enum is a great way to define the phases for a PhaseAnimator. So drop, squish, expand, and rise for this example. Then add properties for each of the attributes you want to animate. For this example, first add the y offset the properties. Return the value at the end of each phase.

    At the end of the rise, the ball is 40 points higher than its original position. At the end of the squish, the ball is five points lower.

    At the end of the other two phases, the ball is in its original position. Next, add a property for the ball's scale.

    When squished, the ball is a bit wider and a bit shorter than its normal shape.

    Otherwise it's round after defining the phases. Add a PhaseAnimator to a view.

    Make the animator iterate over all the phases by conforming your enum to CaseIterable and passing all cases to the PhaseAnimator.

    SwiftUI will call the first closure of the animator, passing each phase in turn. So drop, shrink, expand, and rise.

    Next, draw the animated view here. That's the circle. Then apply modifiers reading the arguments from the phase. Here I'm offsetting by the phases y offset value and scaling by the phases scale value.

    Finally, in the second closure, define the animation that should be used during each phase. Here I'm using ease in animations for drop and expand. These are slow at the beginning and fast at the end, and I'm using Ease Out for squish and Rise.

    Those are the four steps for building a phase animation in SwiftUI. Define the phases for each animated property. Define the value at the end of each phase. Draw your view applying animated effects and finally, specify the animation for each phase.

    To learn more about phase animators, check out. Wind your way through advanced animations in SwiftUI from WWDC23. The second custom effect I'll share is a transition to celebrate a person earning a badge in Wishlist.

    This effect is cool, but fast, so I'll play it again.

    SwiftUI can apply a transition when you add or remove a view or replace one with another.

    This badge transition has two major steps. First, write code to replace one view with another. Here, I'll start with a grayscale version of the badge and then replace it with the colored version.

    Create a group to hold the before and after images inside the group. Use an if to show the colored image. If the badge is earned or a grayscale copy of it. Otherwise. Now setting is earned to true will replace the gray badge with the colored one.

    The second step is to animate this replacement.

    To do this, add a transition modifier to the group. This tells SwiftUI to apply a motion effect when the view's inside the group are swapped. There's some built in transitions that you could use here, like opacity or scale. But to make the badge flip, use a custom transition.

    Create a custom transition by declaring a struct that conforms to the transition protocol.

    The transition protocol has just one requirement a body method like the scroll transition modifier I shared earlier. The body of a custom transition takes a content parameter. This is a proxy for the view that's being added or removed. The body also takes a phase which tells you whether the view is appearing or disappearing.

    Inside the body, apply effects to the content proxy using the phase as a condition. The phase has a property is identity. That's true when the view is visible. So to flip the badges, apply a rotation 3D effect with no rotation when phase is identity, otherwise 180 degrees positive or negative, depending on whether the view is appearing or disappearing.

    Apply an opacity modifier to gradually hide or show the badge during the flip.

    With the custom transition defined. Pass an instance of it to the transition modifier.

    Now when I toggle is earned inside A with animation block, the gray badge animates out and the colored badge animates in using the custom flip transition.

    To learn more about creating custom motion effects in your apps, I recommend the video. Create Custom Visual Effects with SwiftUI from web 24. And for design guidance, check out the motion section of the Human Interface Guidelines on developer.apple.com. As you consider where to use motion effects in your apps, use SwiftUI. Built in views and controls, these give you a variety of motion effects. Automatically add modifiers to refine those effects for your app.

    Use state driven animations to react to events and guide people's attention to what's important. Set your app apart with a carefully chosen set of custom animations.

    Thanks for joining me on this tour of motion effects in SwiftUI. I hope it's helped you understand what's possible using SwiftUI. Now please welcome Leah back to the Big Sur stage.

    That was awesome! It's so cool how SwiftUI makes it easy to add personality to an app through motion. I loved the green bouncy face animation. That was awesome. Up next, we'll take a break for lunch, so take some time to enjoy the refreshments. Ask a question or meet someone new. We have a full agenda in the afternoon and we'll meet back here at 1215 Pacific.

    I hope you enjoyed the break and got the chance to ask a question or meet someone new, we have a full and fun afternoon in store. Up next, my colleague Cole will dive into the details on SwiftUI Dataflow. So please join me in welcoming to the stage.

    Good afternoon everyone. My name is Cole and I'm a core technology evangelist here at Apple. And today I'm going to discuss data in your app and how to flow it through to your SwiftUI views. The Wishlist app is a great example that I'll use throughout the day to demonstrate some of the ways that you might encounter data flow in SwiftUI apps.

    The Wishlist app does a lot of the same things with its data that your apps may need, and it takes different approaches depending on the type of data in question.

    I'll explain some of the most important ones first. There are certain places in this app where the state of the interface will change when someone interacts with it. For example, when someone's modifying a trip, the app will need to keep track of whether the UI is in editing mode or not.

    Now there's a few different places where this will come up, like keeping track of when a sheet is shown after tapping a button, or when an alert needs to be displayed. I'm generally going to refer to these cases as Viewstate.

    Now there's also a data model in this app.

    The goal of the Wishlist app is to show all of this rich data from my brilliant trips and activities. For example, this trip to Kyoto shows a bunch of fun activities to do while there like exploring temples, walking the canal paths at sunrise, and more. So I'm going to need to model this data in the app and flow it through to all of my SwiftUI views.

    The app will also need to keep track of preferences that someone sets in the app. For example, the app has a sort button on the list of activities on a trip. You can sort by title by date or whether the activities are completed. The app will need to keep track of the last sorting method that someone chose, so that it uses that same sorting method the next time this view is shown.

    And finally, I want to build an app. Sorry. I want to build an approach for persistence. Persistence is an approach that lets an app save its data to the device's storage, like in a file. That way, the next time someone comes back to the app, all of their changes are still there, even across relaunches of the app.

    So in this session, I'm going to discuss each of these use cases more in detail. This includes data for view state. Building a rich data model, handling preferences and configuration, and a few techniques for persistence.

    By the end of this session, you'll be equipped to reason about each of these use cases, and you'll know patterns that you can replicate to address similar needs in your own apps. So first I'm going to start with Viewstate.

    As I mentioned earlier, sometimes an app just needs to create a piece of data to track the state of the interface itself. These things are often temporary and safe to reset if the view disappears. For example, the sample app tracks whether or not a Trip is in editing mode or not. If someone navigates away from this trip and then comes back to it later, it makes sense that the UI is no longer in editing mode. Even if I didn't tap done.

    Here's another example of state that needs to be tracked in the interface in this app on the Wishlist tab. There's an add button in the toolbar. Now, Curt talked about this button earlier when refining animations. Tapping this button makes a sheet appear where someone can start entering the details of a new Trip to add to the app.

    So the app will need a piece of state to track whether or not the sheet is currently shown on on on the screen.

    Also, the sheet itself has buttons to save changes or cancel adding a Trip, so those actions in the sheet will need a way to update the state so that SwiftUI will dismiss the sheet.

    So here's how this add button is implemented in SwiftUI. With the sheet in the body of WishlistView, there's a SwiftUI button with a symbol label, and I'll need to add some code to the button action to show the sheet.

    to present the sheet itself. I need to use the sheet isPresented modifier which is added to the view.

    Now, before I can complete this code, SwiftUI needs me to make a decision. What is the data that tracks whether or not this sheet is actually shown on the screen right now? Well, this is a great use case for using the at state API. Here's how it works. I'll create a new property called isPresentingAddTrip and decorate it using at state and it defaults to false.

    Using at state tells SwiftUI to create a new piece of data that lasts as long as this view does.

    I'll actually say more about the lifetime of this value in a bit, but for now, now that I've defined that, I can use it in the rest of my view.

    In the button action, I'll set isPresentingAddTrip to true, since tapping the button should always make the sheet appear, and I'll disable the button if the sheet is already being presented by passing the state to the disabled modifier.

    Note that because the view body reads the isPresentingAddTrip value like in this modifier, the WishlistView establishes a dependency on this value. Any time is presenting. Add Trip changes. SwiftUI will update this view.

    I'll also pass the isPresentingAddTrip property to the sheet modifier. This dollar sign notation allows me to pass a Binding to this state, letting this code share this value with the sheet so it can both read and make changes to it. I'll come back to explain more about bindings shortly.

    Decorating a property with at state tells SwiftUI that this property is owned by the enclosing view.

    The value of this property exists as long as the view does, and this is an important point that I just touched on earlier. At state properties match the lifetime of the view in the interface, not the lifetime of the view struct itself. So I'll dig more into how this actually works.

    As Leah discussed earlier today, SwiftUI views are just short lived descriptions, like a template. When the WishlistView appears in the interface, SwiftUI runs its body in order to update the UI on the screen, but then it throws the instance away, and this repeats every time SwiftUI renders the view.

    So why doesn't the isPresentingAddTrip property get reset anytime this view gets Reinitialized since the default value is false.

    Well, that's because SwiftUI gives special treatment to at state properties like this one.

    Behind the scenes. SwiftUI has its own data storage for all of the state owned by views. When SwiftUI instantiates this view for the first time, it allocates space in its internal storage for this property alongside all of the state owned by other views.

    This storage is indexed by the view's identity.

    Think of the identity as corresponding to the lifetime of this view's rendered results on the screen. So the first time SwiftUI renders the view, it assigns it an identity. And when someone navigates away from this view, SwiftUI deletes the entry from its storage. If they come back to the view later, SwiftUI assigns a new identity and allocates a new entry in its storage.

    So here's how this will work with my button that will show a sheet when tapped the first time someone navigates to a WishlistView. SwiftUI allocates storage for this view's isPresentingAddTrip state property using the default value of False.

    Then it instantiates the struct and sets the value of isPresentingAddTrip to match SwiftUI s internal storage, and then runs WishlistView s body to render to the screen, and then it discards the view instance when the person using the app then taps the button. The action closure runs setting is presenting ad Trip to true, but because this is an at state property, this assignment modifies SwiftUI s internal storage and because the body of the view depends on this state, SwiftUI triggers an update, Creating a new view struct populating the value of isPresentingAddTrip with the new true value from internal storage before running body.

    So this internal storage is how SwiftUI maintains state for the lifetime of the view in the interface. Even though the structs themselves are transient.

    Okay, so this internal storage explains how this at state property asks SwiftUI to track a boolean for the lifetime of this view in the interface. But at state isn't just useful within a single view declaration. It can also be shared with other views using something called a Binding.

    This dollar sign in my sheet modifier allows me to access a binding to this isPresentingAddTrip state.

    A binding is just a read write reference to some piece of state in your app.

    They're great When you're creating a view that needs to read a value from its enclosing view and might need to change that value to.

    Bindings are used all over SwiftUI. You'll find them in the parameters for toggles and text fields and the sheet modifier, and more. These are encapsulated controls that depend on this data and can modify it when needed. For example, here's a snippet of the add Trip view, which is the view inside the sheet itself.

    It uses at Binding to receive a reference from the enclosing view to the state that tracks whether the sheet is presented in the view body. There are buttons that can cause the sheet to be dismissed. In order to do this, they set the value of the isPresented Binding to false in their action closure. That causes SwiftUI to update all of the views that depend on the state like mine. Closing view and then leads to the sheet being dismissed.

    Places like my sheet where I just want to track when someone interacts with the interface is a great fit for. At state. It's temporary data that should reset when the view goes away, or when you have objects that should only exist as long as the view does.

    But at state isn't the best fit for other types of data, like my data model. For those cases, you'll want a way to express types of state to SwiftUI that's owned by other parts of your code, not owned by the UI itself.

    So that leads me to my next use case, which is my data model in Wishlist. The data model is the heart and soul of this app. It includes all of the information that people want to come back to the app for, like the names and photos and activities on each trip. Like in this example, the trip object has the name Peru Off-Road and has this gorgeous photo associated with it.

    There are also relationships between these objects. For example, a trip can have multiple activities and activities, have their own attributes like a name and a boolean to track whether the activity is complete.

    So I've created a data model using classes to represent trips and activities in this app.

    Each class has properties to store attributes like name, photos, and dates.

    They also store references to each other in order to model the relationship between these objects. For example, the trip object can have any number of activities associated with it by storing references to them in the activities property.

    And these objects are also editable, as people might change these properties in the UI. Like when someone edits the name of a Trip in a text field.

    I've also created a class called DataSource to manage all of these objects in the app. It's a single place where the app can look up all of the objects that it needs to show in the UI, like getting a list of all of the trips.

    So having a data model like this is a great start. But to really use this data model in SwiftUI, I do need to add one quick thing.

    The data model needs to be able to know when changes to its properties happen, so that SwiftUI can update the UI.

    And this is what the Observable macro is for. With this one line of code, you can give SwiftUI the power to establish Dependencies on the properties in your classes.

    The Observable macro adds update tracking to each of the classes properties. To use it, just decorate each class with the at Observable macro.

    So now that the data model is Observable, SwiftUI can now establish dependencies on model properties directly.

    In this example, the TripCard view takes a reference to the Trip object it should display.

    Note that there's no. At state or at Binding. In fact, there's no decoration at all on this reference. What makes this view work is that inside the view body it reads the trip's photoURL property. This tells SwiftUI that the TripCard needs to update any time the photoURL property changes on this Observable class.

    And this also works through computed properties. For example, let's say I want to use a placeholder photo for trips that don't have a photo saved yet. To handle this in the UI, I could define a computed property on Trip called photoURL or placeholder. This computed property returns a placeholder photo if there isn't one defined for the trip. And then I use that new computed property in the view body instead of the photoURL.

    SwiftUI is able to determine that the underlying property photoURL is red in this view body when the computed property is accessed. So SwiftUI will update TripCard anytime the underlying photo URL is changed.

    Okay, so to recap, this app uses a structured data model of Trip and Activity objects.

    It uses reference types or classes to model each object, so that I can use references to model the relationship between these objects.

    And it's easy for these properties to be editable anywhere in the UI.

    To make data in these classes flow through to SwiftUI, I just add the at Observable macro to each of their definitions. Then my SwiftUI views can just read the properties directly in view bodies.

    Now there's one more thing I need to do. What I've shown so far works great. Once a view already has a reference to an object like a Trip.

    Now, I said earlier that all of these objects are owned by the DataSource class, but how do I tell my views which data source instance to use? Well, I've actually already discussed one of the ways that you can do this. And it starts with at state.

    Recall that at state we'll create an object that exists as long as the view does. So at the top of my app, I could create an at state property that holds a data source object. Putting at state in this app declaration creates an object that exists as long as the app does, and then it can be passed down to the views.

    Now, this might work well for very simple view hierarchies in this app. Different parts of the UI may need to get access to the data source. For example, to get the full list of trips and with a very simple view hierarchy, it's perfectly reasonable to just pass an object like DataSource down to the views that need it.

    But as an app grows in complexity, this approach might start to become cumbersome. An app with many nested layers of use may end up needing to pass and store a reference to the data source, just so it's able to pass it along to the deeper views that need it.

    So to avoid this problem, cases like this can be a good fit for the environment.

    Think of the environment as the essential properties which configure parts of your app, and they don't change very often.

    In this case, I'll create a data source object as state and I'll set that object on the views environment. This configures the views that need a data source with this particular instance.

    This is safe because the data source object itself won't be swapped out very often. It's Observable and there are lots of different views in my app that may need a reference to it. So by putting the data source in the environment. Any view that needs a reference to it can just grab one directly.

    The environment flows through the entire view hierarchy that it's applied to. A view just has to ask for a value from the environment and SwiftUI will provide it. For example, deeper in the view hierarchy, the RecentTripsPageView gets a reference to the data source by decorating a property with at environment. SwiftUI will populate the value of this reference with the object of a matching type from the environment.

    Since DataSource is Observable, a view can then establish dependencies on its properties right from within the view body. Here, the recently added Trips property is read in this view body, so the recent trips page view will update any time a new trip is added to the app.

    So Viewstate and my data model cover a lot of the data flow that I need in this app so far. But there's a couple of other use cases that take a slightly different approach. And so I'll continue with talking about preferences and configuration in this app.

    I mentioned earlier that when someone taps on a Trip, they can sort the list of activities that appear by name or by whether they're completed.

    The app will need to store this preference so that anytime someone comes to this view, it uses their preferred sorting method. Now, preferences aren't a great fit to go inside the data model that I discussed earlier, because this doesn't really have anything to do with the trips themselves. It's something that tracks how people prefer to use different features of the app.

    So to build this sorting feature, I could start by defining a new piece of state using at state to track what sorting method is being used.

    In this example, it's called sortOption. And then the Activity Subview will read the sortOption when laying out its activities.

    Now this works and the activities are now sorted by what someone chose in the menu.

    But recall that at state properties like this one are only stored for the lifetime of the view. So if someone leaves this view and then comes back to it, the sorting will always revert to the default, which is by title. I want to make it so that anytime someone comes back to the Trip detail view, it's sorted in the same way they selected before.

    So to do this, I'll change at state to at AppStorage and provide a unique identifier for the setting.

    At AppStorage works really similarly to at state. It declares a piece of state that is global to your app, and it works best with simple Codable types.

    AppStorage values actually get stored to disk automatically. Under the hood, it uses an API on Apple platforms called User Defaults, which stores a set of keys and values for your app.

    And this is a great place for settings, preferences and app configuration details.

    So now by by saving the sorting preference in an app storage property, the activities now always sort by the last option that someone chose in the view, even as they navigate across many different trips.

    Finally, the last use case that I'd like to discuss today is persistence.

    The example I just showed you where I saved that sort preference by using AppStorage is actually an example of persistence. SwiftUI will automatically use the User Defaults API to get the value of this key on disk, and then set the value in the view to match.

    And if the sortOption is assigned a different value, AppStorage will save that new value back to User Defaults. So even if someone were to come back to your app a day later, or a week later, or a month later, the sortOption property will remain the same until it's changed.

    But of course, it's not just preferences that you might want to persist. This app has this rich data model, and people are definitely going to want to keep their Wishlist saved for days or weeks or more.

    So to build a data model like this with persistence in your app, one great option is SwiftData.

    SwiftData is a framework that lets you add persistence to your app quickly, with minimal code and no external dependencies.

    It uses modern Swift language features like macros and property wrappers, and that lets you describe your models just by writing Swift code.

    By default, it leverages Core Data's proven persistence. Technology and models in SwiftData are all automatically observable.

    To learn more about SwiftData, check out the videos, meet SwiftData, and build an app with SwiftData.

    As I shared earlier, the data model is comprised of a few classes, and each of its attributes and relationships to each other are stored as properties on each of these classes. And currently these classes are decorated with the Observable macro.

    but if I wanted to make them persist using SwiftData, I would just replace the Observable macro with the model macro.

    The model macro turns these classes into SwiftData models. And again, this automatically makes them Observable as well.

    So as a fun exercise, you can try downloading the sample code when it's available and going through a few steps to migrate this app over to SwiftData. For those of you interested in doing that, I'll explain a few of the key things you'd want to change in the code. First, you'll want to add some metadata to your model. You'll refine how data is fetched or queried from inside the app's views, and you'll set up a container to store your models in. So I'll touch on each of these steps quickly.

    First, after switching the model from at Observable to at model, you'll go through the models and annotate properties where you'd like to give SwiftData more information about them. For example, in the Trip model, you can use at relationship on the activities property to define the relationship between trips and activities. Here I set the delete rule to cascade so that when a trip is deleted, all of its activities are also deleted.

    I've also set the inverse relationship on the trip property to sorry, the inverse relationship of the trip property on Activity. So this means that the trip property on these activities will always point back to the trip that it belongs to.

    Now, SwiftData makes it super easy to fetch and display models within a view by using at Query. You can just ask SwiftData for an array of models sorted and filtered the way you want.

    In this snippet I've updated the RecentTripsPageView I showed earlier. Now, it used to use the data source object to get a list of recently added trips, but with SwiftData I can just use at Query instead.

    This query asks SwiftData to provide an array of trips sorted in descending order by creation date.

    The view body then uses this recently added trips array in a ForEach.

    SwiftData will update this view if the query result changes, like when a new trip is added to the view.

    And finally, in your app declaration, you'll configure your app with a container to store models in by adding the model container modifier and passing the names of your model types. The app will use a default container for its models, so these three changes. Adding a property metadata. refining queries and then adding a model container are the keys to get started. And this brings SwiftData powerful persistence to an app like this one.

    So now I've covered all of the data flow use cases for the Wishlist app, and you're empowered to take similar approaches in your SwiftUI apps as well.

    When a view in your app just needs to track simple UI state, like when a button was tapped, use at state and then use bindings to let other views or controls share that piece of state.

    Consider using the Observable macro for rich data models that you're building with reference types like classes.

    When you want to save data. So save data to storage so that it sticks around. Use AppStorage for small things like settings and preferences. And consider the SwiftData framework for your model data. Thank you for your time. Hope you enjoy the rest of your event. And back to Leah. Yeah.

    That was awesome. It's so important to take the time to learn the basics of data flow and when to use each tool.

    Up next, we have a special guest, James Graham, the CTO of AllTrails, will share about their experience adopting SwiftUI from a complex, mature UIKit app. Please join me in. Welcome James to the stage.

    Good morning or good afternoon everyone. I have a question for you. Maybe this resonates. Have you ever looked at your legacy UIKit code base? Maybe a huge view controller written four years ago and thought, yikes, this needs a serious refactor. Let's just put a pin in this and rebuild the whole thing. And SwiftUI quick show of hands. Has something like this happened to you? Wow. A lot. I see a lot of a lot of hands raised. I'm sure there's more online watching. It's a tempting thought, but at the scale we operate a rewrite, whether it's from an engineer's effort or an AI native workflow, it introduces a huge risk. So hi, my name is James Graham. I'm the CTO at AllTrails, and today I want to talk to you about how we achieved modern velocity without a rewrite. I want to show you how we let SwiftUI adopt us rather than forcing adoption from the top down. Before we dive in, here's the shape of the story. First, I'll share what AllTrails is, our scale and our constraints. Then I'll talk about how SwiftUI entered our code base without a rewrite or a mandate. After that, I'll show you the tipping point. When SwiftUI stopped being an experiment and started becoming the default choice.

    And finally, I'll close with what things look like today and how we view our hybrid architecture.

    To understand our technical decisions, you have to understand our scale. Today, AllTrails is the world's most popular and trusted platform for outdoor exploration. Our mission is simple to help the world find its way outside. We help people discover trails, navigate confidently and elevate their experiences on the trail. With up to date details of the trail and features like photo tours, which highlights photos along the way. Whether it's a walk in your local park or a multi-day hike, we've got you covered. AllTrails has over 90 million community members. We have 500,000 trails worldwide, and our members have logged over 1.9 billion miles.

    We're available in 14 languages, and this means every technical decision we make affects millions of members across different devices, different regions, and, crucially, different connectivity levels.

    We serve a wide spectrum of members with different interests and preferences. On one hand, we have the casual member looking for an easy and relatively flat afternoon walk with a nice view of a local lake, and on the other, we have an avid hiker who's tackling an all day Half Dome hike, navigating offline with no cell phone service.

    That diversity creates strict constraints around reliability, battery life, and UI performance. We cannot ship broken code, but our app isn't static. It's constantly evolving with new surfaces and new feature depth.

    By the time SwiftUI arrived, it promised. AllTrails was already a very large and mature, successful UIKit app. As an example of that evolution, here's our home page over the years.

    We were shipping with weekly release cycles and we were powering both free and paid experiences.

    And here's the most important thing that I'll say about our legacy code UIKit wasn't a problem to be fixed. It was the foundation that enabled our scale. Because of that, we couldn't shut down the trail and make changes. We had to maintain it and we had to upgrade it. Mid hike.

    When SwiftUI arrived, it promised things we desperately wanted. Cleaner state management views that automatically update and when data changes. Eliminating that whole class of bugs where UI falls out of sync with the model less code. We're talking about a 40% reduction compared to UIKit equivalents. That's 40% less code to maintain, to update, and to read.

    Live previews the ability to iterate on design changes instantly, but rewriting a mature app wasn't an option technically or organizationally. We needed a different approach. So SwiftUI entered our code base quietly. It wasn't a mandate or a roadmap item. We created a sandbox, and we used it for low risk experimentation for prototypes and isolated services. It gave us a place to learn the framework without betting our release candidate on it.

    The first real decision wasn't UIKit or SwiftUI. It was how do they thrive together? We invested early in interoperability. Take a look at this code snippet here.

    This is our bridge. We take a SwiftUI feature like our trail coordinator. We wrap it in a HostingView and we drop it right into a standard UIKit StackView.

    And then we add it to the ScrollView.

    As we scroll down the page here, you can see some sections of the HostingView that contain the SwiftUI Subviews. We established this pattern early.

    This was a process decision, ensuring the boundaries were clear and the two worlds could speak the same language.

    Over time, two parallel tracks form naturally. UIKit still handles the heavy lifting for us. App life cycle navigation and complex or deeply integrated surfaces like our trail page or our community Activity. View in a mature app. It didn't make sense to rewrite stable, battle tested screens just to change frameworks, so we avoided rerouting of a well marked trail mid hike and focused our new investments where it delivered clear user and velocity gains on the SwiftUI side. We intentionally are using it where it fits best on those isolated, well bounded surfaces, rendering heavy views and new experiments.

    You can see two examples of that here. The trail review flow is a self-contained surface with dynamic state and UI updates, which maps well to Swiftui's declarative model.

    The Ask the trail anything experience built on Apple Intelligence is a newer, more experimental service. SwiftUI lets us iterate quickly here and evolve the experience without coupling it tightly to the app's core architecture.

    Another area where SwiftUI shines very bright as our design system. Let's take a look at our app in debug mode that visualizes our design system called Denali. Denali is growing larger every day, and we've partnered across our design, system, design, and engineering teams to ensure all new features leverage this system.

    All of our core components, buttons, segments, controls, badges that you see here are part of our design system, viewable in our app in debug mode and now built in SwiftUI.

    What used to take hundreds of lines of boilerplate. Now take a fraction of that. And when we need to add a new variant or adjust spacing, it's a simple change that propagates everywhere. SwiftUI allows us to scale our design system without bloating our code base.

    We also noticed something unexpected happened when we adopted SwiftUI. It started influencing our architecture.

    View models got smaller, often by a third, because we stopped writing glue code just to keep the UI and the state in sync.

    We also wrote a lot less explicit plumbing, fewer publishers, fewer operators, and far less lifecycle management because SwiftUI handled state propagation for us.

    And because UI state and behavior live together, changes touched fewer lines. Our UI pull requests were 30 to 40% smaller and code reviews got noticeably faster.

    That's when SwiftUI stopped feeling like a UI experiment and started feeling like the right way to build systems. We never forced engineers to use SwiftUI. They chose it for their new work because it had less friction. It lowered the cognitive overhead.

    When the choice is right, 40% less code adoption becomes self-sustaining.

    Here's the takeaway for us.

    SwiftUI didn't spread because we told people to use it. It spread because it was the fastest path forward. When a framework lowers cognitive overhead and removes complexity, engineers don't need convincing. We just reach for it.

    But the code base. It didn't flip overnight. It tilted. UIKit remains deeply embedded. SwiftUI grows around it. We measure success metrics like reduction in lines of code per feature, faster iteration cycles, and fewer regressions in those isolated SwiftUI features.

    We realized that interoperability is infrastructure. We invested in hosting wrappers, shared animation, bridges, and unified theming. When the bridge is solid, SwiftUI stops feeling new and starts feeling foundational.

    A perfect example of this is our Apple Watch app. Both our Compass and Map surfaces are built with SwiftUI, and our map uses MapKit. This demonstrates how we can ship critical performance sensitive functionality using modern architecture.

    We chose SwiftUI here not because it was cool, but because it allowed us to iterate faster on a complex surface without touching the legacy navigation logic.

    So where are we today? AllTrails isn't migrated to SwiftUI. You don't need to rewrite your whole app to get the benefits. We're a hybrid system with direction.

    UIKit provides stability. It's still fantastic for deep UI customization like complex collection views or intricate navigation bars.

    SwiftUI defines our growth. It's catching up fast, and our Plant Identification feature seen here is 100% SwiftUI.

    So everything I've described so far is specific to AllTrails our scale, our members, our constraints. And that's intentional.

    The common mistake teams make is treating adoption like a binary decision. Should we adopt SwiftUI? The better framing is. Under what conditions does adoption create momentum instead of risk? When we looked at what actually worked for us fewer bugs, faster delivery, better cross team scaling. It wasn't a single technical choice. It was a set of decisions made deliberately.

    One question I hear a lot is can UIKit and SwiftUI coexist safely? And from what I've shown today, the answer is most certainly yes. So instead of telling you what to adopt, I'll leave you with three questions you can use to evaluate adoption in your own context. One is interoperability treated as infrastructure? If interoperable interoperability is fragile or ad hoc, adoption will stall the moment real product pressure hits.

    Two. Does the new tool reduce cognitive overhead? When a tool genuinely simplifies mental load, adoption doesn't need enforcement. Engineers will choose it voluntarily.

    And three are you measuring momentum and not conversion? Momentum shows up in smaller PR's, faster reviews and fewer regressions. Not in how much of your code base you've converted.

    So if there's a takeaway here, it's that you don't need a rewrite to make progress. You need direction. So thanks so much for your time today and for letting me share the AllTrails story. We'll see you on the trail.

    Thank you so much, James. It's inspiring to hear firsthand how SwiftUI makes it easier to ship features and reduces the maintenance, and that SwiftUI can exist so smoothly alongside a UIKit code base. I'm a big fan of AllTrails, and it's fun for me to learn more about how it's made behind the scenes.

    All right, we're going to take one more break and then meet back here at 225 Pacific for a panel with leaders in SwiftUI engineering. I'll see you then. I hope you enjoyed the break. And now it's time for our panel with three leaders in SwiftUI engineering. So please join me in welcoming Nick, Russell and Taylor to the stage.

    Nice Leah.

    So I've had the pleasure of working with you all before, but for our audience, please introduce yourselves and tell us a little bit more. How long have you been at Apple? Oh well, my name is Nick Tyler. I've been at Apple for about six years. I initially joined the MapKit team and that was already a dream come true, because I had just learned about how MapKit engineers had kind of pioneered object oriented programing, and there really is still the opportunity to work with people who were at Next and Apple back in those days. And so that's, that's how I got brought in. Very cool. I'm Russell I'm a SwiftUI manager now, but I was I've been at Apple for nine years and I primarily was an engineer on UIKit for most of my career here until very recently. And, but came here straight from college. And I'm Taylor, I guess I get to be the oldest here by being 13 years. I also started on MapKit similar to Nick way back when moved into SwiftUI and and most recently actually come full circle, bringing back some MapKit and catalyst responsibilities. So really excited to be here. I feel like you're all telling the interoperability interoperability story between MapKit, UIKit, and SwiftUI just by virtue of your history and experience. So talk a little bit more about what motivated you to transition and work on SwiftUI and what you love about the framework. Well, after working with the Appkit people who were pioneering object oriented design, I saw Taylor off on another team pioneering declarative framework design. And so I really thought that was the next place to go. Yeah. I mean, add on to that, I think, you know, declarative, like the declarative nature really is what kind of drew me in as well. And especially like how it was powered by Swift. Like you could write a declarative system and maybe to back up like by when we say declarative, we mean, you know, you're telling the framework what you want to have happen rather than all the steps to get there, which is the imperative way of building things. And so this was like a really powerful idea that you could build a declarative system in any language, including Objective-C. But Swift made it feel even more natural and expressive to write this. And so it was kind of a unique opportunity to really explore these ideas. And that is what drew me in as well. Yeah. Oh, sorry. I didn't want to cut you off. Oh, I also just see it as kind of like sort trying to solve the same problem I've always been interested in solving, which is making it easier to make apps in the UI. Frameworks are not even so different from each other. And it's not even like SwiftUI doesn't have imperative aspects to it. Like if you drop down into the layout protocol or canvas or path, like there's, it's just a, having a declarative API is another layer of abstraction that's useful for solving the kinds of problems we've always been trying to solve. Russell has a dream he always talks about of like a bug free future where apps, apps just do what you want them to do and everything is right in the world. Yeah, I want to live in that reality. You have a way in. Can you hook me up? I think it's this. I mean, we've got the logo and everything. Like it's it's big. Well, I loved how you described the simplicity that SwiftUI strives for and in my opinion, achieves from the first moment that I use the framework, the declarative interface is it makes it not just graceful, but fun to learn and invest time in.

    So SwiftUI was introduced in 2019. Can you share more about the problem it intended to solve? And then also how that that problem statement and approach has evolved over time.

    I'll jump. Taylor. You've got you've got the seniority, right? Yeah. Most years, I mean, I think, you know, the problem I was trying to solve was kind of making it, lowering the barrier to building apps, right. And taking advantage of things like the declarative system. You know, we've described how like we really want a single source of truth so that you don't end up with the types of bugs you might end up otherwise end up with in other types of apps. So there's really these goals. We're at the heart of a lot of what we were doing. And so the first few years was really setting a foundation of these principles to build from. And then every year after that is about adding additional capabilities. You know, there's a very long history of capabilities that UIKit and Appkit provide. And our goal is to match those. We're not even there yet to this day, but I think we're reaching a point where I'm impressed with the type of apps people can build. To add on to what Taylor said, I think one thing that's been consistent from the beginning is we write the APIs so that, you know, we've got the tagline learn once, write anywhere. But there's also this idea that once you're familiar with parts of the framework, you become familiar. You're automatically familiar with a lot of other parts of the API. So you can imagine back to UIKit, where you've got Uitableview and you learn all about the Uitableview API surface, and then you move to another component and you're like, oh, this has kind of other different patterns I need to become familiar with. But with SwiftUI, the idea is everything kind of feels familiar from the start. And so that's been that's been a steady, a steady. Like a driving force. Yeah. And I think that extends not just to actually using the APIs, but also taking one piece of code and bringing it to different platforms and different hardware and able to able to see your apps presence in different contexts and build your skill set.

    I think one thing that Russell was calling out in another discussion was, you know, as we reach towards the end of kind of having the full feature set that apps expect is kind of going to like a next layer. And I think we're kind of shifting towards that movement of what are the really unique things that you can build with SwiftUI and the types of tools? Yeah. Because, I mean, I think when we started, we, we got like a kernel of a good thing out there. Like once the idea was like really solid, but then there were many years of just getting parity with the other frameworks. And like, I think now as we're approaching that, we can shift priority toward back towards even some of like the core, like what are new ideas that we can bring into the framework and evolve like the core framework itself? Yeah, absolutely. Something that comes to mind for that for me is the, the ScrollView APIs that were introduced and how and you could speak to them better than I, but kind of taking it to that next level of making it easier for the developer to implement really sophisticated views without that much code. And yeah. You're very glad you touched on that. Quick question for the audience. How much of you in your apps are you using SwiftUI and you've got a Geometryreader inside your ScrollView. There it is. Put them up. Nice. All right. I've seen some hands. You probably don't need that anymore. There are other APIs that have existed for for two years and longer that are designed explicitly to make this a more ergonomic and possible. And so are you. Talking about the scroll position modifiers. Scroll position modifiers. There are really neat ways to kind of tie your animations and drive your animations by ScrollView, and we have there's sessions for that as well. In the past you might have to go back to 2023. But anyway, we. Throw it out. View a line scrolling page. Page line. Scrolling Curt did it, scroll. Target behavior, scroll, target layout. Even the layout protocol itself was addressing some of the needs that like the Geometryreader required. So I think these are great examples that show like the feedback loop as well. Like when we see how people are using things and running into trouble, it allows us to think about what's the next step to improve the framework as well, which is. Allow someone to do something really cool where you can. I can't explain it exactly at the moment, but you use coordinate spaces and you can access the coordinate space of the ScrollView through, I think the scroll proxy. So the scroll reader proxy and do a lot of interesting stuff with that without having to have that invalidation cycle that Geometryreader can sometimes bring. I feel like we could go on for ScrollView forever. You know, there's a lot to talk about, but I want to go back to something you said in the impact of developers and seeing how people use the framework and wanting to make SwiftUI not just have parity with UIKit MapKit, but actually go to that next level and make it easier to make delightful experiences. Could you talk about the impact that the developer community has on SwiftUI? That was the original reason. When I said Taylor, I would like to join your team. He was like, what do you like? And I said to me, the UI and SwiftUI doesn't stand for user interface. It stands for you and I. And that's. But it really is true. Like, it's just like when you meet anyone and you have like a shared hobby and you meet anyone and they're like, you're both runners or you both like a certain movie genre. Like I've met so many people in like other countries as I'm traveling around who I've just reached out to because we both like UI frameworks and you immediately have this shared language. So it's honestly like a great way to kind of see the world and meet people.

    Yeah. I mean, I think this like feedback loop that I described earlier of like every year we get to release what we think are the next most important things, see what people are building and how they respond and iterate from there. I mean, like I said earlier, the original goal was lowering the barrier to entry to building apps. And even though that was a goal, we were still kind of impressed and surprised that like once we released SwiftUI, there were people building apps for the first time that never did before. You know, designers was one group of people like this and many others. You know, the generative AI tools are another good example that have really empowered people to, you know, every day I'm seeing like, I built this new app that I really did something I wanted. And it's the first time I've ever built an app. And it's so cool to see that and then see, you know, what are the things that those new types of people building apps run into and how can we make that experience even better? I mean, I even add to that, the whole reason I wake up in the morning is to add new things so that y'all can build wonderful apps. I mean, I came from the developer community myself before I worked here. It was like one of the things I did, how I learned how to code was reading Apple's documentation for how to make how to make iOS apps. I mean, making something move on the iPhone screen was a lot more magical than the terminal app I was playing with before. So I mean, continuing to add to that is maybe someday I'll graduate back to getting to make apps. Yeah. When we say like at the end of our videos, a lot of the times we'll always say like, we can't wait to see what you build. It's really true. One of the most delightful things is where you spend the whole year studying and building this API, and you have your in your head, you've envisioned how people are going to use it, and then you see someone like, here's what I did with this API and you're like, oh, and then.

    That was like a good like. At first you're like, I didn't expect it to go that way. And then they're actually doing something really cool that, and that really means that we've met our goal to in terms of kind of making a compositional API that behaves generally in ways you can do things unexpected. Unexpected. That's awesome. No, the evolution of the framework is it's been a joy to see not just like how sophisticated it's become, but how delightful. And I love events like this where we get to connect with developers both here and online, ask questions and and really see how these APIs are being used and what they're doing great, and how they can continue to better serve the needs of your app. So I think it's super rewarding. And I'm going to speak for all of us. It's rewarding. It's really rewarding.

    So this is a question on Slido. A lot of people were asking about an endorsement for a recommended app architecture in SwiftUI. Could you share more about that? We get this one a lot, and I think the world's come a long way since we could kind of try to recommend one architecture and say one size fits all, and then we send people down this road of this one architecture. And it turns out maybe your app is extremely server driven. And so that architecture wasn't the right move for you. So SwiftUI goal is really to provide the building blocks that every architecture needs. Like we're well aware of all the architectures the community is building. One thing I like to call out is that the at Observable macro is kind of the place to start when you're. If you've got a ViewModel based architecture like use at Observable, use that atomic building block and its first class integration with SwiftUI to build your Viewmodels. And also Observable can then be used kind of in UIKit without loss of generality, which is, which is really nice too. And reinforcing this is the whole like one of the key goals is interoperability. I mean, we saw this story of AllTrails of how they adopted SwiftUI incrementally. And that's true for, for so many apps. And each of those apps are coming from a different place app architecture wise. And it is truly so important that SwiftUI is able to be catered to wherever an app is coming from. Yeah. Even within Apple, so many apps rely on that interoperability. Yeah for sure. It's really what, what lets your team, what, what clicks with all the individual people on your team and how they like to build fastest and what they think is most elegant. And there's so many resources, like if your app is in the UI UIKit land or the MapKit land today, and you're thinking about when to step into the pool of SwiftUI adoption. There are so many resources on the developer website WWDC videos to help guide you through that process. It's a really well-traveled path, and I think there's so many great resources to take that first step. Yeah.

    So I have another question from Slido. And this is more high level. A lot of people were asking about specific, you know, what is the API for this behavior on a specific platform? Or how do I do this functionality in my views? And I'm curious at a higher level, how do you recommend that people find the API for different behaviors with SwiftUI? What tools do you recommend? I've been, I've been having a lot of success with the various model integrations into Xcode. That's at least. That's a great place to start. You can always say because you get to say in whatever language you're speaking. Actually, actually, I don't I haven't seen the models tested in various language, but you have to say in natural language what you're looking for, and then you immediately get kind of a grab bag of, of modifiers and suggestions. And that is actually a really helpful place to start. Yeah. The intelligence features are so cool and they really reduce the barriers for prototyping. That's something I find just to like get started moving in maybe an area that I'm not as well versed and then can further refine my understanding. The latest releases are really cool in that regard, but I do think it's an important thing that, you know, it's going to produce something, it's going to try to show you something, but it is your job as the developer to kind of question that and like, make sure you understand what it's doing. We're all familiar with things like hallucinations and things like that. And so in addition to like verifying that, I think it's also a powerful learning tool, which is, I think how you started this, which is okay. It suggested these set of modifiers to achieve this effect. Do I understand what each of those are actually doing? And that can lead you into the documentation. And one of our goals is making sure each piece of documentation describes it has a little piece of sample code. So you can yourself start to build up a mental model, you know, driven by this type of learning, which I think is cool. Yeah. And that's what we're here for today. The foundations, like I think I've said that word about ten times today, maybe more. We'll count it. But like taking the time to understand the foundations helps you have the confidence in your code. And then if you don't understand something, maybe the LMM produces it. You can still take that time to, to find exposure to areas that you aren't as confident in yet and learn it. So it's really cool. That's one thing. Yeah, especially when you're trying to learn. I'm almost never learning and writing the app at the same time. Like I'm always learning with Xcode previews. And then once, once you get the foundation, then you take that into the app where you have all that other side effects and complexity happening at the same time, but at least you have that model for how it's how it's supposed to work. So when things seem off, or you might have done something weird, you know, kind of where to look and where to start. Yeah. previews is one of my favorite tools, not just the fact that it makes it easy to isolate, state, and reproduce bugs. Maybe there's like, like some odd behavior and I could just quickly inject state and see how it's behaving, but quickly prototype and like for layout, I love using previews for layout. It's one of my favorite tools. Another resource that just came to mind is the developer forums. So in addition to documentation and the Wwdc videos, which is really not just how I learn about different APIs, but also just see them in the larger context of a sample app and see how the different pieces come to mind. Like that. ScrollView video was awesome because I came up with so many ideas for animations, but the developer forums are also a great resource because you can ask questions by the framework like SwiftUI or UIKit, but you can also ask platform specific questions like watchOS or Vision OS. And even if you don't have a question in that moment, maybe you just want to learn and get some awareness to the kinds of things you could be thinking about in the future. It's an awesome resource, and Apple engineers and support team are moderating that. So it's a great reference as you're building and continuing your journey as a developer.

    So I want to also talk a little bit about SwiftUI helping apps stay modern this year with Liquid Glass, that was a big part of the iOS 26 story and other operating systems. Could you share more about how SwiftUI helps apps stay modern for Apple platforms? Do you want to? I mean, first I can just say that there's a. Like a SwiftUI provides a lot of higher level semantic APIs, higher level than even the UIKit and Appkit provided in the past, which lets us provide a lot more flexibility so that when your app is implemented with these semantic concepts, things like I mean, even even prior to Liquid Glass dynamic type dark mode, these like adaptive concepts, when those things change, your app just updates and Liquid Glass is just it has many wonderful components, but it's also a theme in many ways. And so it doesn't necessarily change the core structure of your app. And implementing it with these semantic concepts lets it just just update.

    But there's also like it applies to custom controls as well. So even if you do make something custom, there's that that might need some adaptation. But there's other APIs like glass effect container that like SwiftUI in particular enabled beyond the way that the other frameworks have because of our like our extremely composable APIs. The API surface for glass. Glass effect container is very small. It's there's, I think there's the one view. And then maybe 3 or 4 public modifiers. And, and yet it's like this. It has all these transitions and like pieces that can merge and morph together. And you can imagine like how an imperative UI framework might struggle to deliver an API that was as concise, understandable that used as many pieces that already existed. So I think SwiftUI has really helped us with Liquid Glass. I think this goes back to Nick called out this phrase of learning once and applying anywhere. And it doesn't just apply across frameworks, but even like within this concept, it's like all of these animation techniques you might have learned for some other purpose apply equally in this context. And so I think it's another good example of that, that principle life. Yeah. To me, I think it's like knowing when to reach for the containers and knowing kind of those, again, the foundations, it keeps coming up these knowing those foundations to reach for and then knowing exactly where to sprinkle in your branding or what makes your app special and making sure that's kind of robust to the passage of time, because operating systems evolve and you want to make sure that you're not kind of, you're not stuck with a lot of work to change depending on how you architected your app. And so if you kind of push those unique experiences in the right spot, then you can take your. If you've got a very fancy animation. When you tap the like button, something jumps up and spins and dances. Then that's immediately across all platforms and very robust to change and very future proof. Yeah, something that struck me through the workshops with developers, the Liquid Glass workshops, is that if they had built with native components like the Tab View and using system controls, that just recompiling with iOS 26 automatically set those apps, whether they were UIKit or SwiftUI, up in a great spot to start taking advantage of Liquid Glass look modern on Apple platforms and. And then get to start going to the next level of refinement and thinking of opportunities to maybe revisit navigation or revisit branding. And that was really cool. Like it felt kind of magical. And I think it's really great that that's part of Swiftui's foundation as a framework, removing that barrier to stay modern and take advantage of the sophistication of the operating system. I think one measure we've looked at is like. The time spent doing just the things to make your app look like it's part of the platform. We want to decrease this as much as possible so that you're spending all your time on what really makes your app unique. I think that's a great way of showing that. Yeah, absolutely. Could you talk a little bit more about system components? Like I think there's really a lot to tease out there in Wishlist the the sample app today there Majo discussed it in her design presentation. There's a lot of core system components like the tab, the Tab View that we kept really clean using SF Symbols for the icons and, and letting the app lean into the familiar standard system architecture. But then we use typography in different fonts to express personality and branding. Could you talk about how you recommend people navigate those trade offs, when to use built in controls versus express a little bit more personality? Oh, that's a good one.

    Boy. And there's a lot to go into because it depends. Yeah. It really. I was gonna say it really is a design decision of like, where, where do you want your app to be unique? Where do you want it to feel familiar? I think there is a benefit to the familiarity because like somebody who's downloading your app for the first time, you want them to be able to have have it be familiar, not have to learn how to use your app uniquely. And then there are the little experiences that that kind of draw them in, right? That make it stand out. That's a great lens. I feel like to look at it through is like, I Russell Russell did a whole lot of work. He built a lot of UI presentation controller and sheet and SwiftUI sheet and sheet is just one of my favorite components for that because people, to Taylor's point, they just know how it's going to work. It's such a core piece of the operating system that I really hesitate to provide global guidance. But try not to build your own sheet. Right? Yeah, there's. No that. That's trustworthy. And not just for me. Not just for you. Okay. I'll take your word for it. Well. There's a theme over the last several questions that I think of progressive disclosure, where both like both from the user's perspective, like the more things you use that are in common with other apps than the user can better understand how your app works. But also in the API, like if you, if you use a higher level semantic component, then it will both be more familiar to like to you and everyone that uses the app and adapt more. But it's also easier for, for you as the developer to understand because it's, it's, it's a simpler, higher level concept. And if you drop down into building increasingly into customizing that thing more and more for your use case, then it's, it becomes more complex for, for, for everyone, maybe appropriately so, but we want to ensure there's like a continuum. And so adding more like ways to appropriately customize the high level components such that you don't have to like fully drop down is very important, and I think I was connecting this to whatever the last thing we were saying was. But no, I felt it, I felt it. I mean, something that came to mind for me is that there's also a lot you can do with the system components, like talking about sheets and some of the beautiful behavior with iOS 26, like how the background changes a little bit based on the height of a sheet. You can there's a lot of tools that exist to customize the behavior of a sheet and modifiers. So sometimes you can get, and it takes a little time to read the documentation and find out what options exist. But like you can set the presentation detente, is it detente or detent? I always struggle, that's my secret. I always struggle with it. The creation. Of this API. Word. Detente. Okay, I'm slowing it down. It's detent. Oh, it's. See, I. Was like a micropipette. I was. Like a. Micropipette. But, you know, there's a lot you can do that's built into the API to get a really sophisticated behavior and customize these built in navigation tools and these built in controls to express personality in your app. Things like view modifiers, fonts, like there's so much that you can do with this system components. And there are still limits, which we want you to hit and find and tell us. And we're listening so that we can remove those limits and make it even more powerful. That's totally. True. One of my favorite things that she does, especially with Liquid Glass, is, as you might have to correct me here, as it grows taller, it becomes more opaque. But the sheet itself is glass. And like, depending on the height of the sheet, it kind of nestles right into the device bezel or is floating depending on how big it is. And it's like, it's very, it's very. Nice. There's a lot of behaviors we've added to sheets over the years. Are you the king of sheets? Is this. No. Well, there's many of us that work on sheets to make that component work. Yeah. No, it's it's beautiful. I, it's such a joy to see how thoughtfully a lot of these system components are are reimagined with iOS, with the 26 operating systems and with Liquid Glass. And it's also been fun for me to look at Cat mentioned earlier the joys of like looking at an app that you think is neat and you're and doing that exercise of saying, this looks cool. I'm going to try to build this by myself in SwiftUI. It's kind of like that empty page problem. Like you, maybe you want to build skills with layout or with data flow, and you don't really know where to start. And you're wondering, do I need a design? You know, and that's kind of the first problem you solve. But doing some that independent exercise to try to build something by yourself from scratch is, I think, a great way to gain experience and cement that learning. Yeah. So true. I did that the other day with the, the app on the home screen of iOS, the app wiggle animation. Like when. You hold something down. Yeah. And they lock into edit mode and it kind of. Moves all three. I want to see who does the best like this. It's random. It's really hard to get right. I think it's Russell. Yeah. Russell. It's not just a repetitive curve. And so just implementing that on a square in SwiftUI is kind of a fun exercise. And I'll give you a hint. I'm pretty sure you're going to need the the should merge property of custom animation that's advanced. I was thinking of baz animation. Okay, cool. Yeah. It's mentioned in dub dub video for animation. That's that's really. Phase might be a very valid way of doing it to. See. And there's multiple ways to solve a problem too. Like I think that's something that's really fun to do. Sometimes I'll try to redo something and maybe I'll start with one approach and it's kind of there and I'll keep going and I'm learning along the way and these incremental approaches. I think it goes back to the whole progressive disclosure that that Russell mentioned, which is like a core principle of the API design itself, but it's like even pushing yourself to the next layer, like you try to do a thing, oh, you've gotten pretty close. What's the next thing you can try to learn about and experiment with to, to make it even closer to what you wanted or bring a new, unique element into it? Yeah, I feel like no matter what level of experience someone has with SwiftUI, whether they're just starting out or their experience and trying to solidify their understanding, there's always more to learn and discover, both with just the new APIs and and finding more interesting ways to implement things. Yeah. Very cool. So I have one last question for both, for all of you. We've been talking about Wishlist a lot today and different trips and the stuff that we want to do on these trips. Lots of activities, lots of travel. What is your next vacation? I'm very much hoping to see Scotland this year. I've never, never been. I want to see the countryside. I want to drive on the left hand side of the road.

    That's a dream of yours.

    Some Scottish slang. You can. You can, you can. What does that mean? I think that's like, you know. Okay, learning more. You got to test that out when you get there and see if it goes. If there's anyone in the audience who knows. Come find me. At the mixer. Very cool. I actually don't know my. Okay, shout out to all the Sagittarius out in the audience. My. My birthday's over the holidays and so my sister planned a deferred surprise trip later this month, and I don't even know where we're going, so we'll find out. That's an adventure. And and Wishlist, you could just put like question marks for all the Activity. It could just be like a random number generator. You never know what's coming next. That could be a future. Yeah, yeah. So I'm one of those people who doesn't like to relax on my vacations. As ironic as that sounds, I'm sure. You're an active vacation person. I'm an active vacation person. And so we like to do different hikes. And so one of our upcoming ones is we want to do a multi-day hike through the Dolomites in Italy. That's one. No plans yet. We want to figure out when we can do that. Nice. That sounds great. We've got like two international trips and a big mystery Russell. Maybe you're maybe your trips to Cupertino or somewhere. I guess we'll find out. Yeah, we'll have to follow up soon. Well, thank you all so much. Could you all join me in giving them a round of applause? This was I. I learned so much and it's so much fun to talk about SwiftUI. Well thank you.

    It is so much fun to learn more about SwiftUI, not just from the technical details, but the story behind the framework.

    Today was an action packed day. We covered foundational concepts of SwiftUI from the visual layer, with design and layout and motion all the way down to dataflow. And at every step, we covered the theory behind the decisions in real apps like Wishlist, James Graham shared firsthand how SwiftUI helped AllTrails ship and maintain features more efficiently throughout all these chapters. I hope one thing remains clear take the time to invest and learn the foundations of SwiftUI. It will help you work with the framework to make your apps great.

    My colleagues and I are so grateful that you took the time to learn with us today on Slido. We answered over 200 questions and to continue the conversation, check out the Apple Developer Forums where you can ask questions about SwiftUI and more.

    The code for the Wishlist app will be available for download in the coming weeks. It's a super fun app to play with, whether you're planning your next trip or revisiting some of the exercises from today's presentations.

    My colleagues and I mentioned certain videos and documentation during the presentations, and later today, we'll send out an email with the links to the resources so you can keep learning.

    One of the best ways to learn about SwiftUI and other technologies is through videos from WWDC.

    There are hundreds of videos, and you can watch them on the Apple Developer website or in the developer app. You might even notice some familiar faces from today's presentations.

    It's been an action packed day. But before we go, I have one more special guest.

    You might have seen her before in the keynote, or so too, as well as our recent Swift Student Challenge launch. She'll share a few words and help us close out the show. Please join me in welcoming Susan Prescott, VP of Apple Developer Relations.

    Hey! I am so excited. First of all, about my job. I hope you all love your job too. But it is super fun as you can see. Hopefully throughout the day today. And there's many more people that weren't part of this today. There is a lot of passion and commitment to the developer community in this organization around the world, and I hope today was one of the days you could really feel it. I want to say thank you for being here, which you've already heard from a bunch of people. I want to say thank you to all of the people who participated on stage, including James from AllTrails gets a little gold star for being here and sharing his his experiences as well. So I have to ask, was it a good day for you guys? Unofficial survey. Like how was it? Do we have to do like Robert's Rules of Order? And now I have to ask the people who want to boo to go or can we just skip that? I'm glad I could feel the energy in the room. I could feel the energy from the audience. And I just just love that. So as Leah will explain in more detail, we have an opportunity after this. For those of you who are here in person, we love those of you who are participating online as well, and that matters a lot. So hey, and we love you. You're going to have to get your own glass of juice because here we'll have a mixer for everybody. And yes, there'll be some light refreshments. But I think the most exciting part is that the people that you've seen on stage, and many other folks who work at Apple in the engineering and developer relations teams are here to talk with you. And you all have opportunities to meet each other as well, because the community isn't, you know, hub and spoke from Apple. It's all you guys together. And then us being part of it where we can. So anyway, I'm going to hand it to Lisa, to Lisa, to Leah to close. I just want to say thanks and I'll see you guys out at the mixer. So thank you. Yeah.

    Thank you all. So much for joining us today in Cupertino and online. You're the heart and soul of our developer community. I hope you learned something new and have ideas for what to explore next. For everyone joining in person. We'll meet outside in a moment for some refreshments and a chance to connect with Apple engineers and designers. To all of you, whether in person or online. We hope you'll join us again soon, either online or at an Apple Developer Center near you. Thank you.

Developer Footer

  • Videos
  • Meet with Apple
  • SwiftUI foundations: Build great apps with SwiftUI
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • AI & Machine Learning
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    • Documentation Archive
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Follow us on bilibili, LinkedIn, WeChat, and YouTube.
    Copyright © 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines