Hey there, I have a problem running multiply tasks in parallel in a SwiftUI view.
struct ModelsView: View {
@StateObject var tasks = TasksViewModel()
var body: some View {
NavigationView{
ScrollView {
ForEach(Array(zip(tasks.tasks.indices, tasks.tasks)), id: \.0) { task in
NavigationLink(destination: ModelView()) {
ModelPreviewView(model_name: "3dobject.usdz")
.onAppear {
if task.0 == tasks.tasks.count - 2 {
Task {
print(tasks.tasks.count)
await tasks.fetch_tasks(count: 4)
}
}
}
}
}
}.navigationTitle("3D modelle")
}.onAppear{
Task {
await tasks.fetch_tasks(count: 5)
await tasks.watch_for_new_tasks()
}
}
}
}
In my view, I spawn a task as soon as the View Appears which, first, fetches 5 tasks from the database (this works fine), and then it starts watching for new tasks.
In the Scroll View, right before the bottom is reached, I start loading new tasks.
The problem is, the asynchronous function fetch_tasks(count: 4) only gets continued if the asynchronous function watch_for_new_tasks() stops blocking.
actor TasksViewModel: ObservableObject {
@MainActor @Published private(set) var tasks : [Tasks.Task] = []
private var last_fetched_id : String? = nil
func fetch_tasks(count: UInt32) async {
do {
let tasks_data = try await RedisClient.shared.xrevrange(streamName: "tasks", end: last_fetched_id ?? "+" , start: "-", count: count)
last_fetched_id = tasks_data.last?.id
let fetched_tasks = tasks_data.compactMap { Tasks.Task(from: $0.data) }
await MainActor.run {
withAnimation(.easeInOut) {
self.tasks.append(contentsOf: fetched_tasks)
}
}
} catch {
print("Error fetching taskss \(error)")
}
}
func watch_for_new_tasks() async {
while !Task.isCancelled {
do {
let tasks_data = try await RedisClient.shared.xread(streams: "tasks", ids: "$")
let new_tasks = tasks_data.compactMap { Tasks.Task(from: $0.data) }
await MainActor.run {
for new_task in new_tasks.reversed() {
withAnimation {
self.tasks.insert(new_task, at: 0)
}
}
}
} catch {
print(error)
}
}
}
...
}
The asynchronous function watch_for_new_tasks() uses RedisClient.shared.xread(streams: "tasks", ids: "$") which blocks until at least one tasks is added to the Redis Stream.
I tried running the watch_for_new_tasks() on a Task.detached tasks, but that also blocks.
To be honest, I have no idea why this blocks, and I could use your guy's help if you could.
Thank you in Advance,
Michael