I am trying to understand what the rule is when calling Task { ... } and, in that task, calling await in terms of threads.
This example works:
struct TaskTestView: View {
let url = URL(string: "https://www.google.com")!
@State private var message = "Loading..."
var body: some View {
Text(message)
.task {
/// on MAIN THREAD
do {
var receivedLines = [String]()
for try await line in url.lines {
/// on MAIN THREAD
receivedLines.append(line)
message = "Received \(receivedLines.count) lines"
}
} catch {
message = "Failed to load"
}
}
}
}
This does not:
struct TaskTestView: View {
@StateObject var model = TaskTestViewModel()
var body: some View {
Text(model.message)
.task {
/// - here it is on main thread
await model.refresh()
/// - here it is NOT on main thread
print("after refresh: on main?")
}
}
}
class TaskTestViewModel:ObservableObject {
let url = URL(string: "https://www.google.com")!
@Published private(set) var message = "Loading..."
func refresh() async {
do {
var receivedLines = [String]() // on main thread
for try await line in url.lines {
receivedLines.append(line) // NOT on main thread
message = "Received \(receivedLines.count) lines"
}
} catch {
message = "Failed to load"
}
}
}
- Why does the code run on the main thread after line
for try await line in url.lines {in the first example? - Why does the code NOT run on the main thread after that same line but in the second example?
How would I know the answer to those questions without running the code and putting a breakpoint to inspect the thread I am on?
Obviously the main issue here is that I want to make sure I update @State variables on main so the view works properly, but, not having this concept clear makes it hard to design proper patterns.