首页 > 解决方案 > 从核心数据中删除/添加到核心数据后,带有列表的 SwiftUI TabView 不刷新

问题描述

描述:

当从上下文中删除列表中的对象(从 fetchrequest 创建)并保存上下文时,列表不会正确更新。

错误:

线程 1:致命错误:在展开可选值时意外发现 nil(在下面的第 5 行抛出)

struct DetailView: View {  
    @ObservedObject var event: Event  

    var body: some View {  
        Text("\(event.timestamp!, formatter: dateFormatter)")  
            .navigationBarTitle(Text("Detail"))  
    }  
}  

重现步骤:

  1. 使用 SwiftUI 和 Core Data 创建一个新的 Master Detail App 项目。

  2. 在 ContentView 中,将 body 设置为 TabView,第一个选项卡是预构建的 NavigationView,然后添加第二个任意选项卡。

struct ContentView: View {  
    @Environment(\.managedObjectContext)  
    var viewContext     

    var body: some View {  
        TabView {  
            NavigationView {  
                MasterView()  
                    .navigationBarTitle(Text("Master"))  
                    .navigationBarItems(  
                        leading: EditButton(),  
                        trailing: Button(  
                            action: {  
                                withAnimation { Event.create(in: self.viewContext) }  
                        }  
                        ) {  
                            Image(systemName: "plus")  
                        }  
                )  
                Text("Detail view content goes here")  
                    .navigationBarTitle(Text("Detail"))  
            }  
            .navigationViewStyle(DoubleColumnNavigationViewStyle())  
            .tabItem { Text("Main") }  

            Text("Other Tab")  
                .tabItem { Text("Other Tab") }  
        }  
    }  
}  
  1. 添加一些项目。以任何方式与这些项目互动。
  2. 更改选项卡。
  3. 改回主选项卡。
  4. 尝试删除项目。

标签: swiftgenericscore-dataswiftui

解决方案


我找到了一个纯 SwiftUI 工作解决方案:

/// This View that init the content view when selection match tag.
struct SyncView<Content: View>: View {

    @Binding var selection: Int

    var tag: Int

    var content: () -> Content

    @ViewBuilder
    var body: some View {
        if selection == tag {
            content()
        } else {
            Spacer()
        }
    }
}

您可以通过以下方式使用它:

struct ContentView: View {  
    @State private var selection = 0  

    var body: some View {  
        TabView(selection: $selection) {  

            SyncView(selection: $selection, tag: 0) {  
                ViewThatNeedsRefresh()  
            }  
            .tabItem { Text("First") }  
            .tag(0)  

            Text("Second View")  
                .font(.title)  
                .tabItem { Text("Second") }  
                .tag(1)  
        }  
    }  
}  

您可以对需要刷新的每个视图使用 SyncView。


推荐阅读