从我的角度来看,我正在调用一个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: …
我正在尝试新的 async/await 东西。我的目标是test()在后台运行该方法,所以我使用asyncDetached; 但是在test()我需要在主线程上进行调用时,所以我使用了 MainActor。
(我意识到这可能看起来很复杂,但它是从一个更好的现实世界案例中缩减而来的。)
好的,所以测试代码看起来像这样(在视图控制器中):
override func viewDidLoad() {
super.viewDidLoad()
asyncDetached(priority: .userInitiated) {
await self.test()
}
}
@MainActor func getBounds() async -> CGRect {
let bounds = self.view.bounds
return bounds
}
func test() async {
print("test 1", Thread.isMainThread) // false
let bounds = await self.getBounds()
print("test 2", Thread.isMainThread) // true
}
Run Code Online (Sandbox Code Playgroud)
第一个print说我不在主线程上。这就是我所期望的。
但是,第二个print说,我是在主线程上。那不是我所期望的。
感觉好像我神秘地回到主线程只是因为我调用了一个 MainActor 函数。我以为我会等待主线程,然后在我已经在的后台线程中恢复。
这是一个错误,还是我的期望错了?如果是后者,怎么做我时走出主线程await,但再回来线程我是吗?我认为这正是 async/await 可以简化的事情......?
(在某种程度上,我可以通过在调用 …
我\xe2\x80\x99m 正在学习Swift async、await、 。@MainActor
我想运行一个很长的过程并显示进度。
\nimport SwiftUI\n\n@MainActor\nfinal class ViewModel: ObservableObject {\n @Published var count = 0\n\n func countUpAsync() async {\n print("countUpAsync() isMain=\\(Thread.isMainThread)")\n for _ in 0..<5 {\n count += 1\n Thread.sleep(forTimeInterval: 0.5)\n }\n }\n\n func countUp() {\n print("countUp() isMain=\\(Thread.isMainThread)")\n for _ in 0..<5 {\n self.count += 1\n Thread.sleep(forTimeInterval: 0.5)\n }\n }\n}\n\nstruct ContentView: View {\n @StateObject private var viewModel = ViewModel()\n\n var body: some View {\n VStack {\n Text("Count=\\(viewModel.count)")\n .font(.title)\n\n Button("Start Dispatch") {\n DispatchQueue.global().async {\n …Run Code Online (Sandbox Code Playgroud) 我们希望在现有的 SwiftUI 项目中使用@MainActorViewModel 的注释,这样我们就可以摆脱DispatchQueue.main.async和.receive(on: RunLoop.main)。
@MainActor
class MyViewModel: ObservableObject {
private var counter: Int
init(counter: Int) {
self.counter = counter
}
}
Run Code Online (Sandbox Code Playgroud)
从 SwiftUI 视图初始化带注释的类时,这种方法效果很好。但是,当使用 SwiftUI Previews 或 XCTest 时,我们还需要从上下文外部初始化该类@MainActor:
class MyViewModelTests: XCTestCase {
private var myViewModel: MyViewModel!
override func setUp() {
myViewModel = MyViewModel(counter: 0)
}
Run Code Online (Sandbox Code Playgroud)
这显然不能编译:
主要参与者隔离属性“init(counter:Int)”无法从非隔离上下文中进行变异
现在,显然我们也可以按照此处的建议MyViewModelTests进行注释。@MainActor
但我们不希望所有的单元测试都在主线程上运行。那么在这种情况下推荐的做法是什么?
如果我们不想在初始化器中设置变量的值,则按照上面对话中建议的init方式注释函数才有效。nonisolated
我想了解是否需要考虑以下代码块将任务本身声明为 MainActor。
func login() {
Task { [weak self] in
let result = await self?.loginService.start()
if result == .successful {
self?.showWelcomeMessage() // updating the UI here
}
}
}
final class LoginService {
@MainActor
func start() async -> LoginResult {
// Doing some UI related operations here
}
}
Run Code Online (Sandbox Code Playgroud)
当任务内部调用的异步函数已经声明为 MainActor 时,我是否还需要将任务本身声明为 MainActor ?像这样:
func login() {
Task { @MainActor [weak self] in
let result = await self?.loginService.start()
if result == .successful {
self?.showWelcomeMessage() // updating the UI here
} …Run Code Online (Sandbox Code Playgroud) 如果正在上课@MainActor:
@MainActor class MyClass : NSObject
{
}
Run Code Online (Sandbox Code Playgroud)
这是否也将其所有扩展都打开了@MainActor?
extension MyClass
{
}
Run Code Online (Sandbox Code Playgroud) mainactor ×6
swift ×5
async-await ×4
ios ×3
concurrency ×2
swiftui ×2
asynchronous ×1
swift5.5 ×1