SwiftUI @MainActor 失去全球演员

kit*_*ian 11 concurrency multithreading swiftui mainactor

从我的角度来看,我正在调用一个ObservableObject@StateObject。该类内部有一个函数,整个类都被标记为@MainActor。在我看来,有一个TextFieldwithonChange修饰符,可以通过 执行调用该函数viewModel.funcname

Xcode is complaining with an error of:

Converting function value of type '@MainActor (String) -> Void' to '(String) -> Void' loses global actor 'MainActor'
Run Code Online (Sandbox Code Playgroud)

I've been researching this for hours now and have found little to nothing. Even Apple's own docs say to simply use await but that doesn't work, at least not the many ways I've tried it.

This is the code within my view:

    TextField("", text: $viewModel.username)
        .onChange(of: viewModel.username, perform: viewModel.editingChanged) // This is where the error occurs
Run Code Online (Sandbox Code Playgroud)

This is the function in my class (remember that the entire class is marked @MainActor):

func editingChanged(_ value: String) {
            
    let jsonFetchUserExistsURL = URL(string: "https://blah.com")
    let jsonFetchUserExistsTask = jsonFetch(jsonFetchUserExistsURL, defaultValue: [UserExists]())

    guard isNetworkActive else { loadingAlert = true; return }
        Task {
            jsonFetchUserExistsTask.sink (receiveCompletion: { completion in
                switch completion {
                    case .failure:
                        self.loadingState = .failed
                    case .finished:
                        self.checkUser()
                }
            },
            receiveValue: { loadedUserExists in
                self.userExists = loadedUserExists
            }).store(in: &requests)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

I have tried modifying the onChange to read as follows:

.onChange(of: viewModel.username, perform: await viewModel.editingChanged)
.onChange(of: viewModel.username, perform: Task { await viewModel.editingChanged })
.onChange(of: viewModel.username, perform: Task.detached { await viewModel.editingChanged })
.onChange(of: viewModel.username, perform: DispatchQueue.main.async { viewModel.editingChanged })
Run Code Online (Sandbox Code Playgroud)

The entire reason I marked the class @MainActor is because Xcode complained that the function wasn't running on the main thread. It compiled but froze after it complained a few times in the console.

Nothing I've tried seems to change anything. Hoping someone can shed some light on this.

jn_*_*pdx 8

请参阅我对有关策略是否是@MainActor解决根本问题的正确方法的问题的评论,但要直接解决编译错误,您可以使用以下语法,该语法可以正常编译:

.onChange(of: viewModel.username) { viewModel.editingChanged($0) }
Run Code Online (Sandbox Code Playgroud)

  • 有人可以解释为什么这有效吗?闭包不是“@MainActor”,所以编译器不应该要求调用“editingChanged”是异步的吗? (2认同)