A SwiftUI TabView contains to two tabs. Each displays data from the same model. If the data is missing, a ProgressView is displayed, if the data is present, the current value is displayed. In the example model the data is set asynchronously after 2 seconds to cause the problem. (In my real app, the data is set as a result of an async call.)
After running the app, the first tab is displayed containing the ProgressView and the data is displayed after 2 seconds. So far everything seems to work. When switching from the first Tab to the second the app crashes somewhere 75 levels deep in SwiftUI display code:
(AG::Graph::add_indirect_attribute:) with EXC_BAD_ACCESS.
What am I doing wrong and how can I circumvent the problem, if it is an SwiftUI Bug?
The following code causes the crash:
import SwiftUI
import Combine
class Model: ObservableObject{
@Published var value:Double?
init(){
DispatchQueue.main.asyncAfter(deadline: .now() + 3){
self.value = 2.0
print("value set")
}
}
}
@main
struct TabViewUpdatingTestApp: App {
@StateObject var model = Model()
var body: some Scene {
WindowGroup {
ContentView(model: model)
}
}
}
struct Tab: View {
let name:String
@ObservedObject var model:Model
var body: some View {
if let mvalue = model.value{
Text("name: \(name), value: \(mvalue)")
}else{
ProgressView().font(.largeTitle)
}
}
}
struct ContentView: View {
@ObservedObject var model:Model
var body: some View {
TabView {
Tab(name: "Tab 1", model: model)
.tabItem {
Label("Tab 1", systemImage: "1.circle")
}
Tab(name: "Tab 2", model: model)
.tabItem {
Label("Tab 2", systemImage: "2.circle")
}
}
}
}
It looks like a bug to me. A possible workaround may be to force-refresh the TabView
:
struct ContentView: View {
@ObservedObject var model: Model
var body: some View {
TabView {
Tab(name: "Tab 1", model: model)
.tabItem {
Label("Tab 1", systemImage: "1.circle")
}
Tab(name: "Tab 2", model: model)
.tabItem {
Label("Tab 2", systemImage: "2.circle")
}
}
.id(model.value) // add here
}
}
Alternatively, instead of redrawing the view when model.value
changes, you can create some other variable that changes only once (so you don't refresh the TabView
every time but only once at the beginning).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With