Skip to content

[SR-14764] @MainActor ignored by the compiler #57114

Closed
@DevAndArtist

Description

@DevAndArtist
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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itself

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions