最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - How do I call an async function on the main actor? - Stack Overflow

programmeradmin1浏览0评论

Ok ... so I want to call an async function in my .onAppear function

import SwiftUI
import RealityKit
import RealityKitContent
import MyFoo

struct ContentView: View {
    
    @Environment(MyFoo.self) private var foo: MyFoo

    @State private var message : String?
    
    var body: some View {
        VStack {
            Model3D(
                named: "Scene",
                bundle: realityKitContentBundle
            ).padding(.bottom, 50)

            if let msg = self.message {
                Text(msg)
            } else {
                Text("No message yet.")
            }
        }
        .padding()
        .onAppear(perform: connectToMyFoo)
    }
    
    @MainActor
    private func connectToMyFoo() {
        DispatchQueue.main.async {
            Task {
                await self.foo.initialize()
                // ...
            }
        }
    }
}

But Swift doesn't let me.

First of all, DispatchQueue.main.async for some inexplicable reason still expects a synchronous closure. THEN if I try to start a task within that to get around it, it loses the isolation and complains that

Passing argument of non-sendable type 'MyFoo' outside of main actor-isolated context may introduce data races; this is an error in the Swift 6 language mode

A message I am growing exceedingly tired of, as I've wasted WAY more time than I care to admit trying to make it go away.

So if not like this, HOW do I run foo.initialize() in the main actor isolate when the whole bloody language doesn't want to cooperate?!

Run foo.initialize(). Do it on the main actor. Wait until it's done. It shouldn't be so bloody hard.

Ok ... so I want to call an async function in my .onAppear function

import SwiftUI
import RealityKit
import RealityKitContent
import MyFoo

struct ContentView: View {
    
    @Environment(MyFoo.self) private var foo: MyFoo

    @State private var message : String?
    
    var body: some View {
        VStack {
            Model3D(
                named: "Scene",
                bundle: realityKitContentBundle
            ).padding(.bottom, 50)

            if let msg = self.message {
                Text(msg)
            } else {
                Text("No message yet.")
            }
        }
        .padding()
        .onAppear(perform: connectToMyFoo)
    }
    
    @MainActor
    private func connectToMyFoo() {
        DispatchQueue.main.async {
            Task {
                await self.foo.initialize()
                // ...
            }
        }
    }
}

But Swift doesn't let me.

First of all, DispatchQueue.main.async for some inexplicable reason still expects a synchronous closure. THEN if I try to start a task within that to get around it, it loses the isolation and complains that

Passing argument of non-sendable type 'MyFoo' outside of main actor-isolated context may introduce data races; this is an error in the Swift 6 language mode

A message I am growing exceedingly tired of, as I've wasted WAY more time than I care to admit trying to make it go away.

So if not like this, HOW do I run foo.initialize() in the main actor isolate when the whole bloody language doesn't want to cooperate?!

Run foo.initialize(). Do it on the main actor. Wait until it's done. It shouldn't be so bloody hard.

Share Improve this question asked Feb 10 at 10:04 User1291User1291 8,2298 gold badges64 silver badges132 bronze badges 2
  • 1 Either use dispatch queues and old-school completion handlers, or use async/await, tasks, and actors. Do not try to use dispatch queue code like DispatchQueue.main.async in new style async/await code. – Duncan C Commented Feb 10 at 16:28
  • @DuncanC You're missing the point. The whole dispatch queue, @MainActor annotation, etc. is just an attempt to somehow get rid of the darn error that doesn't want to be got rid of. I DID try to make connectToMyFooasync, but then Swift STILL complains that I'm passing a "non-sendable" foo "outside of the main actor-isolated context". So HOW do I bloody KEEP it in the "main actor-isolated context? Like in actual, helpful terms. "Use async", no offence, is about as helpful as a stubbed toe. – User1291 Commented Feb 11 at 2:45
Add a comment  | 

1 Answer 1

Reset to default 2

Define that the function initialize() runs on the main actor

@MainActor 
func initialize() async {
    //...
}

and execute it from a task modifier instead of using DispatchQueue.main.async

.task {
    await self.foo.initialize()
}
发布评论

评论列表(0)

  1. 暂无评论