Description
Previous ID | SR-14764 |
Radar | rdar://problem/79352544 |
Original Reporter | @DevAndArtist |
Type | Bug |
Status | Resolved |
Resolution | Done |
Environment
Version 13.0 beta (13A5154h)
swift-driver version: 1.26 Apple Swift version 5.5 (swiftlang-1300.0.19.104 clang-1300.0.18.4)
Target: arm64-apple-macosx11.0
Additional Detail from JIRA
Votes | 0 |
Component/s | Compiler |
Labels | Bug |
Assignee | None |
Priority | Medium |
md5: 489030d069b5154dcc245685ee400a89
Issue Description:
Compiler seems to ignore `@MainActor` in the following code example:
import SwiftUI
class Model: ObservableObject {
@Published
var data: Data?
}
struct TestView: View {
@ObservedObject
var _model = Model()
@MainActor
func apply(_ data: Data) {
// runtime warning:
// Publishing changes from background threads is not allowed; make
// sure to publish values from the main thread (via operators like
// receive(on:)) on model updates.
_model.data = data
// runtime crash
dispatchPrecondition(condition: .onQueue(.main))
}
func fetchData() async throws {
let urlString = "https://google.com"
guard case let url? = URL(string: urlString) else {
return
}
let (data, response) = try await URLSession.shared.data(from: url)
guard
case let httpResponse? = response as? HTTPURLResponse,
httpResponse.statusCode == 200
else {
return
}
// note there is NO `await` here as the compiler does not ask for it at all
apply(data)
}
var body: some View {
Text("\(_model.data.map(\.count) ?? 0)")
.task {
do {
try await fetchData()
} catch {
print(error)
}
}
}
}
I can try adding `await` infant of the `apply` call, but this results into a `No 'async' operations occur within 'await' expression` warning.
I can apply two workarounds:
-
Make `apply(_: )` method `async` and add `await` infant of it as the compiler correctly would ask for, but this doesn't make sense as this should be a non-suspendible synchronous method just to hop back to the main thread and sign the value.
-
I can move `@MainActor` to the entire type and make `fetchData` as `nonisolated`, which works as intended, but the original example should also work and require the `await` keyword.
Discussion on the forum: https://forums.swift.org/t/mainactor-ignored-by-the-compiler/49533