recently I’ve played around with SwiftUI (I’m not a Swift developer, this topic is quite new for me). I’ve found out strange behavior with a dispatch queue.
In my project, the business logic is match more complex; however, here is a simple example (see below).
The issue is the following: if you try to click the button frequently, the value of the actual boolean variable & the view could be different (see the attached screenshot below).
Could anybody give me a hint, what can I do with such an issue?
Note: the main app class is in comments to this post.
ContentView.swift
import SwiftUI
struct ContentView: View {
@StateObject var model = ContentViewModel()
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(model.isCondition ? .green : .red)
Button("TOGGLE") {
model.foo()
}
.buttonStyle(.borderedProminent)
}
}
}
ContentViewModel.swift
import SwiftUI
final class ContentViewModel: ObservableObject {
@Published private(set) var isCondition: Bool = true
private var queue = DispatchQueue(label: "My Queue", qos: .background)
func foo() {
queue.async { [self] in
isCondition.toggle()
print("isCondition = \(isCondition.description)")
}
}
}
View (states) are required to be updated on the main thread when the body of the view is being computed. So try this approach, where you do your processing on your queue,
but update the View
state on the main thread.
struct ContentView: View {
@StateObject var model = ContentViewModel()
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(model.isCondition ? .green : .red)
Button("TOGGLE") {
model.foo()
}
.buttonStyle(.borderedProminent)
}
}
}
final class ContentViewModel: ObservableObject {
@Published private(set) var isCondition: Bool = true
private var queue = DispatchQueue(label: "My Queue", qos: .background)
func foo() {
queue.async { [self] in
// ... do calculations/processing here on your queue
// but update isCondition on the main thread
DispatchQueue.main.async {
self.isCondition.toggle()
print("isCondition = \(self.isCondition.description)")
}
}
}
}