Live activity sample code for Swift 6?

Hi, I'm updating our app to use Xcode 16 and Swift 6 language mode. I'm stuck on updating our live activity code. I looked at the Emoji Rangers sample project and after switching it to Swft 6 mode, it has the exact same errors as our project.

The main problem seems to be that Activity is not Sendable, which prevents us from passing it to child tasks to await things like activityStateUpdates and contentUpdates (those are also not Sendable).

Is there any guidance on this? Updated sample code? Another project?

Emoji Rangers is quite large, and converting all of it to Swift 6 is a challenge. You should feel free to file a bug against the sample requesting that, but on DevForums I prefer to focus on specific problems.

Is there a specific issue you’re trying to resolve? If so, can you pull that out into a small test project that reproduces it?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

The Integrating CarPlay with your quick-ordering app might be the closest sample project but it is not optimized for Swift 6.

Rico

WWDR - DTS - Software Engineer

Ok, specific problem then. I downloaded Emoji Rangers, switched language mode to Swift 6, udpated some static vars to static lets, commented out the contents of ImageURLProtocol.stopLoading and finally got to the issue in AdventureView.swift:

This error is the one I can't seem to solve - Main actor-isolated value of type '() async -> Void' passed as a strongly transferred parameter; later accesses could race. As far as I understand it, here it basically means that something that is not Sendable is being sent between contexts.

It is not possible to remove @MainActor here because activityViewState is isolated to it:

And even if this was not a factor, the original error reappears once activityViewState is no longer in the picture:

The only workaround I've found feels wrong:

extension Activity: @unchecked @retroactive Sendable {}

I spend a bunch of time looking at this today, and eventually boiled it down to this:

import ActivityKit

struct TestAttributes: ActivityAttributes {
    struct ContentState: Codable & Hashable {
    }
}

@MainActor
func observeActivity(activity: Activity<TestAttributes>) async {
    await withTaskGroup(of: Void.self) { group in
        group.addTask { @MainActor in
           // ^ Main actor-isolated value of type '() async -> Void' passed
           // as a strongly transferred parameter; later accesses could race
            for await activityState in activity.activityStateUpdates {
                print(activityState)
            }
        }
    }
}

The easiest fix seems to be to change the addTask(…) line to look like this:

group.addTask { @MainActor @Sendable in

I dug much deeper into that and I’m not 100% sure why the compiler needs this. I’ll probably research this some more but, for the moment, the above should be sufficient to get you going.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Live activity sample code for Swift 6?
 
 
Q