【问题标题】:SwiftUI @MainActor loses global actorSwiftUI @MainActor 失去了全局演员
【发布时间】:2022-06-14 18:35:55
【问题描述】:

在我看来,我有一个 ObservableObject 类,我通过 @StateObject 调用它。该类内部是一个函数,整个类标记为@MainActor。在我看来,有一个带有onChange 修饰符的TextField 可以通过viewModel.funcname 执行对该函数的调用。

Xcode 抱怨以下错误:

Converting function value of type '@MainActor (String) -> Void' to '(String) -> Void' loses global actor 'MainActor'

我已经研究了几个小时,几乎没有发现任何东西。甚至 Apple 自己的文档都说要简单地使用 await,但这不起作用,至少不是我尝试过的许多方法。

这是我认为的代码:

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

这是我班级里的函数(记住整个班级都标有@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)
        }
    }
}

我尝试将onChange 修改为如下:

.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 })

我标记类 @MainActor 的全部原因是因为 Xcode 抱怨该函数没有在主线程上运行。它在控制台中抱怨了几次后编译但冻结了。

我尝试过的一切似乎都没有改变。希望有人能对此有所了解。

【问题讨论】:

  • “我标记类@MainActor的全部原因是因为Xcode抱怨该函数没有在主线程上运行”如果jsonFetchUserExistsTask是一个异步操作(我猜它是)并且没有在主线程上返回,似乎与其经历尝试用@MainActor注释然后直接在editingChanged中启动Task,然后在jsonFetch i>另一个线程,你应该在你的sink之前使用.receive(on: RunLoop.main)...
  • jsonFetch 使用 combine 并且已经通过 .receive(on: DispatchQueue.main) 标记为在主线程上运行

标签: multithreading swiftui concurrency mainactor


【解决方案1】:

请参阅我对@MainActor 策略是否是解决潜在问题的正确方法的问题的评论,但要直接解决您的编译错误,您可以使用编译好的语法:

.onChange(of: viewModel.username) { viewModel.editingChanged($0) }

【讨论】:

  • 那行得通。谢谢。现在我正在追查为什么它会突然陷入无限循环。分离出函数来清理代码是一个严重的 PITA。
猜你喜欢
  • 2021-10-13
  • 2022-08-21
  • 1970-01-01
  • 2021-11-14
  • 2022-11-17
  • 1970-01-01
  • 2022-07-21
  • 2015-09-30
  • 1970-01-01
相关资源
最近更新 更多