Must-Watch Sessions From WWDC ’23

Ensure you’re up-to-date on the most important announcements from WWDC ’23 with this round-up of important sessions for developers to watch! By Audrey Tam.

Leave a rating/review
Download materials
Save for later

Another WWDC has come and gone, and there are so many important and compelling session videos yet to watch! Or at least scan.

There are sessions on our most important tools: Swift, Xcode and SwiftUI. The new Observable and SwiftData frameworks will revolutionize how your apps handle data. Accessibility and localization got some notable improvements. And, of course, everyone’s excited about Vision Pro and using visionOS in everything.

Kodeco Team members nominated a few other topics as favorites: Widgets, Swift OpenAPI Generator, Push notifications console and Swift-DocC.

Here’s a roundup of the most important videos from WWDC ’23. Watch them to ensure that you’re up-to-date with Apple’s most important changes this year!

Swift, Xcode & SwiftUI

It’s always worth scanning the What’s new sessions. Even if you don’t start using all the new things right away, you’ll be aware of what’s there, and you’ll know what everyone else is talking about on social media.


First up, What’s new in Swift.

The Chapters links make it easy to jump straight to whatever sounds interesting:

What's new in Swift: Chapters

You can get a quick overview of the updates by scrolling through the code snippets:

What's new in Swift: Code

Tap directly into the video, and the transcript scrolls to match:

What's new in Swift: Transcript

And you can search the transcript for specific terms, then jump right into the video or check out the code.

Macros are the big news in Swift, and they underpin the big news in SwiftUI and SwiftData. Here are two sessions to get you started:

Also take a look at the macro repositories from Doug Gregor and Krzysztof Zabłocki.


Next, What’s new in Xcode 15 — your favorite IDE gets easier to use every year, with loads of productivity enhancements like intelligent code completion, previews, test navigator and test reports, improved navigation, source control and debugging.

For example, read this SwiftLee article about the new Xcode bookmarks:

[A] new feature that allows you to save quick links to code you want to revisit. Doing so allows you to save code landmarks and organize tasks you have to fulfill.

I can feel my workflow shrinking already!

And, whether you love or hate unit and UI tests, be sure to look at Fix failures faster with Xcode test reports to learn about failure patterns, UI automation explorer and UI test video recordings.


SwiftUI keeps getting better and easier to use.

What’s new in SwiftUI

What's new in SwiftUI: Chapters

There are improvements to SwiftUI previews and new SwiftUI support for watchOS, MapKit, Charts and StoreKit, but the big news here is the new Observation framework described in the Simplified data flow chapter and in more detail in Discover Observation in SwiftUI.

We’re back to just three property wrappers: @State, @Environment and the new @Bindable — a lightweight wrapper if you just need to create a binding to an @Observable value — say, to display it in a text field so the user can edit it.

Observable TIL

I’ll quickly walk you through converting the Combine-based ObservableObject protocol to @Observable in a very simple app.

Click Download materials at the top or bottom of this article to download the starter project. Open it in Xcode 15 beta. It would work in Xcode 14, but I’ve already set its iOS deployment target and minimum deployment to 17.0.

TIL is simpler than Apple’s FoodTruck app — it just lets the user add acronyms, which it displays in a list. Refresh the ContentView preview and add a couple of acronyms to see how it works.

TIL with two Things

In ThingStore, change:

final class ThingStore: ObservableObject {
  @Published var things: [Thing] = []

to this:

@Observable class ThingStore {
  var things: [Thing] = []

ObservableObject becomes @Observable, and any public properties will be published. You can mark an accessible property @ObservationIgnored if you don’t want it to be observed.

Apple’s Note: Using the final keyword is optional when making a class observable.

TIL doesn’t let the user edit an acronym after it’s created, so Thing doesn’t need to be @Observable, and it can remain a struct.

In AddThingView, change:

@ObservedObject var someThings: ThingStore

to this:

let someThings: ThingStore

In ContentView, change:

@StateObject private var myThings = ThingStore()

to this:

let myThings = ThingStore()

You no longer need @ObservedObject or @StateObject. When AddThingView updates someThings.things, ContentView will automatically update because myThings is observable, and ContentView reads its things array.

Refresh the preview, then add a few acronyms to see the app works the same as before, but now with a little bit less code.

Observable TIL with two Things

Now, build and run the app in a simulator. Add a couple of acronyms, then stop the running app in Xcode. Reopen the app in the simulator: No Things, no surprise. The app has no persistence code.


No need to mess around with writing and reading plists or files — or worse, grapple with un-Swifty Core Data: Meet SwiftData! Start with this session, then dive deeper with these:

  • Model your schema with SwiftData: Use @Attribute to customize properties, set up @Relationships with other @Models, exclude properties from your data model with @Transient and, when the time comes, migrate from one version of your schema to the next.
  • Build an app with SwiftData: Work with a multi-platform SwiftUI app to convert existing model classes and update the UI with model layer changes. Also, learn how to use SwiftData in document-based apps.
  • Dive deeper into SwiftData: Learn about ModelContext, ModelContainer, FetchDescriptor, SortDescriptor and enumerate.

And, if your apps already use Core Data, take a look at Migrate to SwiftData to learn how to switch to SwiftData or add it alongside your Core Data code.

TIL With SwiftData

And now, to convert TIL to use SwiftData. Continue with the Observable version of TIL.

In TilApp, import SwiftData

import SwiftData

Then add this modifier to WindowGroup:

.modelContainer(for: Thing.self)

You create a model container for the Thing model type. You can also pass an array of model types as the for parameter, to store more than one type. Creating a container also sets a model context in the environment for this container.

In ThingStore, import SwiftData then replace Thing with this:

class Thing {
  // let id = UUID()  // be sure to delete this!
  let short: String
  let long: String
  let alt: String

  init(short: String, long: String, alt: String) {
    self.short = short
    self.long = long
    self.alt = alt

Like @Observable, @Model is a macro. It converts a class into a stored model managed by SwiftData.

You definitely don’t want the id property anymore. It confuses the model and produces wildly incorrect results. And, now that Thing is a class, you need an initializer, even if you assign default values to all the properties. The @Model macro requires an init method.

Comment out ThingStore: The container and context take care of everything.

In ContentView, import SwiftData then replace this property:

let myThings = ThingStore()

with these two lines:

@Environment(\.modelContext) private var modelContext
@Query private var myThings: [Thing]

You bring in the model context and set up a simple query to fetch the array of Things.

Fix the error messages about myThings.things by deleting .things from myThings.things:

if myThings.isEmpty {


ForEach(myThings) { thing in

In the sheet(isPresented:) closure, delete the someThings argument:


You don’t have a ThingStore anymore, and you don’t have to pass anything to AddThingView.

In AddThingView, replace this line:

let somethings: ThingStore

With this:

@Environment(\.modelContext) private var modelContext

You bring in the model context here, too.

And, in the Done button’s closure, replace:

someThings.things.append(Thing(short: short, long: long, alt: alt))

With model context code:

let newThing = Thing(short: short, long: long, alt: alt)

In #Preview, delete the someThings argument.

Now, back in ContentView, add this modifier in #Preview:

  .modelContainer(for: Thing.self, inMemory: true)

Refresh the preview and add a few acronyms to see the app works the same as before. Now, for the magic: Build and run in a simulator, add a few Things, then stop the running app in Xcode. Reopen the app in the simulator to see your Things are still there!

SwiftData TIL with persistent Things