WWDC 2024 has come and gone, which seems to happen quicker and quicker each year, and in its wake are a lot of videos to check out. There were so many videos this year, Apple started releasing them Monday night after the Platform State of the Union, so you knew it was going to be a packed week. It would be impossible to cover all the new material in one article. However, between the Keynote, the Platform State of the Union, and some select videos, here are some things you definitely need to check out. These are in no particular order, but all are must-watches if you’re an Apple developer.
Swift
Swift 6 is the big change this year, although you can luckily adopt the new safe data-race safety conformance at your own pace, module by module, thanks to compiler’s Swift 6 language mode options. In addition to using Swift on embedded devices, improved C++ interoperability, and non-copyable types, two really cool items stood out.
Fully Static Linux SDK for Swift
You can now cross-compile your apps for Swift on Linux and include the Swift libraries as a fully static component of your app. This means the destination doesn’t need to have Swift installed. This can be great for deploying things like web service apps over to a Linux system.
Typed Throws
You can now used typed throws to get better feedback on exactly what error is caught. For example:
enum MyError: Error {
misTyped, whatWasIThinking
}
func foo(string: String) throws(MyError) -> String {
//.....
throw MyError.misTyped(string)
}
do {
let response = try foo(string: "Hello world!")
} catch {
//the error here is of type "MyError" instead of just "Error"
}
For more on Swift this year, be sure to check out What’s new in Swift, and for more on migrating your project to Swift 6, check out Migrate your app to Swift 6
SwiftUI
SwiftUI got a fair number of updates this year, as usual. Here are some of the things that stood out.
View Is now on the @MainActor
You no longer need to mark your views with @MainActor
because the View
protocol now has that decoration. That’s one less line of code to write!
The Magic Floating Tab Bar (or Is it a Sidebar?)
Something that’s already getting a mixed response is the new tab view style:
struct TabBarExample: View {
var body: some View {
TabView {
Text("Tab 1")
.tabItem {
VStack {
Image(systemName: "1.circle")
Text("Tab 1")
}
}
Text("Tab 2")
.tabItem {
VStack {
Image(systemName: "2.circle")
Text("Tab 2")
}
}
Text("Tab 3")
.tabItem {
VStack {
Image(systemName: "3.circle")
Text("Tab 3")
}
}
}
.tabViewStyle(.sidebarAdaptable)
}
}
This can result in one of two images, depending on whether you want a floating tab bar at the top (think visionOS) or a traditional sidebar (think NavigationSplitView):
I haven’t had a chance to play a lot with this one, but as with all paradigm-breaking things, there’s usually a bit of disagreement in the community about it. We’ll see how this one shakes out!
New Modifiers for Presentation and Zooming
For views represented in a sheet, a new modifier lets you specify page, form, or custom sizing:
.presentationSizing(.form)
And to get a nice zoom in animation when bringing views to the foreground, a new pair of modifiers can help you:
.navigationTransition(.zoom(
sourceID: item.id, in: namespace))
///....
.matchedTransitionSource(id: item.id, in: namespace)
}
For more on SwiftUI this year, be sure to check out What’s new in SwiftUI.
SwiftData
SwiftData didn’t have a huge update this year like some were hoping, but it did get some very necessary updates to help with performance and queries. This year, Apple added the ability to specify unique constraints with the #Unique
macro and commonly indexed fields with Index
. With just a few lines of code, you can add those features to an existing @Model
:
import SwiftData
import Foundation
@Model
class KodecoArticle {
#Unique([\.name, \.dateWritten, \.author])
#Index([\.name], [\.dateWritten], [\.author], [\.name, \.dateWritten, \.author])
var name: String = ""
var author: String = ""
var content: String = ""
var dateWritten: Date?
var dateUpdated: Date?
init(name: String, author: String, content: String, dateWritten: Date? = nil, dateUpdated: Date? = nil) {
self.name = name
self.author = author
self.content = content
self.dateWritten = dateWritten
self.dateUpdated = dateUpdated
}
}
The #Unique
line states that entries are unique on that combination of properties, and the #Index
line lists which properties, or combination of properties, are added as extra metadata to the model so it can perform faster queries.
Apple also unveiled other new features for SwiftData, such as using your own custom data store! For more, check out What’s New in SwiftData.
Frameworks That Are Everywhere
There were two strong examples of frameworks that were gaining parity and power over many if not all of the platforms Apple provides. There’s a lot to cover here, so here they are along with links to the WWDC videos.
App Intents
Over the past few years, App Intents has become a major player when it comes to surfacing your app’s features; whether it be to shortcuts, Siri, or widgets.
This year, App Intents gets another upgrade because it’s the mechanism to hook your app into Apple Intelligence. For more, be sure to check out What’s new in App Intents, Bring your app’s core features to users with App Intents, and Bring your app to Siri.
RealityKit
Over the years, RealityKit hasn’t been very uniform across the platforms, making it hard to deploy the same app to different Apple hardware. That changes this year, as RealityKit has a lot of new cross-platform APIs across all the various platforms — visionOS, macOS, iOS, and iPadOS. For more, check out Discover RealityKit APIs for iOS, macOS, and visionOS.
Swift Testing
In addition to moving the open source Swift components to the swiftlang organization at GitHub, Apple has formally included Swift Testing in that family of libraries. Swift Testing is a new way of testing in Swift (but complementary to XCTest), introducing more “Swifty” syntax to your test code. Here’s a quick example:
import Testing
struct WWDCTests {
@Test func testExample() async throws {
let value = 2
#expect(value + value == 3)
let value2: Int? = nil
_ = try #require(value2)
}
}
After importing the Testing
framework, you decorate your tests with the @Test
attribute. This means you no longer need to name your test methods so they start with “test”. I’ve added a few things to test. The first uses the #expect
macro, which replaces the family of XCTAssert calls and checks to see whether the condition inside is true. The next code block checks that value2
is not nil before proceeding by using the #require
macro. See what Xcode says when the test button is clicked:
In the right gutter, you see indications that the expectations failed. For the first one, if you hover over the error, a “Show” button appears that you can click to get more details, as shown in the screenshot. This lets you dive into why exactly the tested code failed.
This looks to be a lot cleaner than XCTest (although you can use both in your tests!), and I can’t wait to start using it. For more about Swift Testing, check out Meet Swift Testing.