Forgive me this iOS only question, but I really do...
# ios
s
Forgive me this iOS only question, but I really don't find the correct solution. 🙈 How can I make that my SwiftUI task runs on the background?
task
is always on the main thread.
Task.detached
starts a new task on another thread. The problem is
Task.detached()
runs to completion even is task is cancelled because the cancellation is not propagated. Can some expert please enlight me how to correctly do that?
Copy code
.task {

      Task.detached {

        guard image == nil else { return }

        image = await imageLoader.loadThumbnailImage(photoUri: photo.uri)
      }
    }
1
h
By reading the docs only: What about
Copy code
.task(priority: .background) {
    Task {
    }
}
s
That still runs on the main actor unfortunately.
It would be so nice if these Tasks would do it like coroutines and automaticly propagate cancellation
h
I thought, they do. But
Task.detached
is
GlobalScope
, which doesn't inherit cancelation too:
Copy code
suspend fun a() {
     while (true) {
        delay(1.seconds)
        println("Still running")
    }
}
    
@OptIn(DelicateCoroutinesApi::class)
@Test
fun b(): Unit = runBlocking {
    withTimeout(5.seconds) {
        GlobalScope.launch {
            a()
        }
    }
    delay(10.seconds)
}
s
Yeah, I'm so confused. Apple changes API all the time and a lot of solutions for that are outdated. 🤷‍♂️
If I could just set the opposite of the MainActor annotation to my imageLoader call. That would be great.
Is there any
withContext()
equivalent in Swift?
h
not similar, but this works: `actor`:
Copy code
import SwiftUI

struct ContentView: View {
    let a = A()
    
    var body: some View {
        Text("Hello, world!")
            .padding()
            .task(priority: .background) {
                print("Start Thread")
                await a.a()
            }
    }
}


actor A {
    func a() async {
        Task {
            print("Start Sleeping")
            try await Task.sleep(nanoseconds: 50_000_000_000)
        }
    }
}
message has been deleted
s
Thank you. 🙏 I guess I need to look up again the whole "actor" mechanics. 😅 Changing my ImageLoaderImpl from "class" to "actor" according to your sample does the trick.
h
Keep in mind, `actor`s handles
async
calls sequentiell!
s
So no concurrent image loadings at the same time?
I improved performance now because if you scroll very fast trough my photo gallery tasks for images that are no more visible do not needed to be loaded. That's why task cancellation is very important here.
Yes, ok. Bringing everything to the same actor is indeed another problem. 😅
Wow, Apple really made this hard
Ok, I hacked this... If you call a kotlin suspend function (you must be on the main thread for that because the others are not supported) when this comes back from "await" you are on an random background thread... then you can do stuff in parallel... until you call a method marked as MainActor to bring you back.
🙈
Let's talk no further about this and let me thank you again, Phillip ❤️
h
Nice 😄