In Swift 6.2, the mental model for nonisolated async functions has changed: a nonisolated async function now stays on the caller's actor by default unless it is explicitly offloaded elsewhere.
Implications:
- Calling a
nonisolated async method on a helper struct no longer implies automatic background execution. - If you require the function to run on the concurrent pool (background) rather than the caller's actor, you must use explicit offloading (such as the
@concurrent attribute).
struct Measurements {
func fetchLatest() async throws -> [Double] {
let url = URL(string: "https://hws.dev/readings.json")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode([Double].self, from: data)
}
}
@MainActor
struct WeatherStation {
let measurements = Measurements()
func getAverageTemperature() async throws -> Double {
// In Swift 6.2, this call stays on the @MainActor
let readings = try await measurements.fetchLatest()
return readings.reduce(0, +) / Double(readings.count)
}
}