swift async function is being run on the main thread in some cases when run from task
Asked Answered
E

2

8

In this case the async function reads a file and returns the parsed contents.

In my view I want to load the contents off of the main thread, and then update the view once complete.

I've used this pattern in various places and noticed that in some cases the async call is on the main thread (by debugging) while in others it is on the Thread 4 Queue : com.apple.root.user-initiated-qos.cooperative (concurrent) thread

For example:

struct MyView: View {
  @State var data = "some data"
  var body: some View {
    Button("refresh") {
    // when the button is pressed refresh it
            Task {
                await refresh()
            }
        }.task {
    // when the view appears
            await refresh()
        }
     Text("the data is \(data)") // write the data which was refreshed async
   }


  }
  func refresh() async {
        do {
            let res = try await anotherAyncFunction()
            data = res // this is presumably wrong and off the main thread - obviously might not be correct but leave here for debug as well
        } catch {
            print("got error \(error)")
        }
    }

I created several different views using a similar pattern (.task block calling async functions)

In some cases the functions are long running (reading from disk) and that is happening on the main thread

Electroshock answered 28/10, 2021 at 12:17 Comment(1)
You might enjoy the video Swift concurrency: Behind the scenes which explores the way Swift Concurrency schedules tasks.Jaclyn
W
7

Change Task { to Task.detached {.

From the Swift Language Guide:

To create an unstructured task that runs on the current actor, call the Task.init(priority:operation:) initializer. To create an unstructured task that’s not part of the current actor, known more specifically as a detached task, call the Task.detached(priority:operation:) class method.

When you call Task.init, the asynchronous code runs on the current actor, which, in this context is the main actor. This has the result of blocking the main thread.

By calling Task.detached, you allow the asynchronous work to happen off the main thread.

Waverly answered 13/11, 2021 at 5:24 Comment(1)
Doesn't work, my Task is detached, yet it is on the main thread.Glauconite
B
3

Using Swift structured concurrency, to run code on a background thread, use a detached task or (better) an actor.

Botvinnik answered 28/10, 2021 at 12:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.