【问题标题】:SwiftUI TabView crashes when displaying tab containing data that changed when said tab was invisibleSwiftUI TabView 在显示包含在所述选项卡不可见时更改的数据的选项卡时崩溃
【发布时间】:2021-04-24 12:56:20
【问题描述】:

一个 SwiftUI TabView 包含两个选项卡。每个都显示来自同一模型的数据。如果数据丢失,则显示 ProgressView,如果数据存在,则显示当前值。 在示例模型中,数据在 2 秒后异步设置,从而导致问题。 (在我的真实应用中,数据是异步调用的结果。)

运行应用程序后,显示第一个选项卡,其中包含 ProgressView,并在 2 秒后显示数据。到目前为止,一切似乎都奏效了。 当从第一个选项卡切换到第二个选项卡时,应用程序在 SwiftUI 显示代码的 75 层深处崩溃:

(AG::Graph::add_indirect_attribute:) 带有 EXC_BAD_ACCESS。

如果是 SwiftUI 错误,我做错了什么?如何规避问题?

以下代码导致崩溃:

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")
                }
        }
    }
}

【问题讨论】:

    标签: ios swift swiftui tabview


    【解决方案1】:

    对我来说它看起来像一个错误。一种可能的解决方法是强制刷新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
        }
    }
    

    或者,当model.value 更改时,您可以创建一些其他仅更改一次的变量,而不是重绘视图(因此您不必每次都刷新TabView,而是在开始时只刷新一次)。

    【讨论】:

    • 谢谢!这可以防止在我的真实代码中发生崩溃,并且因为只有在没有过多重绘的危险时才设置此值。此外,我不知道 id 修饰符。将来进行一些强制重绘可能会很有用。