ios - SwiftUI:创建 CoreData 对象后无法关闭工作表
问题描述
我正在尝试创建一个具有两个视图的非常基本的应用程序。主视图在 NavigationView 中显示 CoreData 对象,并具有用于打开“添加项目”模式表的工具栏按钮。“添加项目”表应该能够插入一个新的 CoreData 对象并自行关闭。我观察到的是,只要模式表不插入 CoreData 对象,就可以关闭它,但是一旦它与 CoreData 交互,我所有关闭工作表的尝试都不再有效。此外,当工作表创建 CoreData 对象时,我收到以下错误:
[Presentation] Attempt to present < TtGC7SwiftUI22SheetHostingControllerVS_7AnyView : 0x7f8fcbc49a10> on < TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier _: 0x7f8fcbd072c0> (from < TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVVS_22_VariadicView_Children7ElementGVS_18StyleContextWriterVS_19SidebarStyleContext __: 0x7f8fbbd0ba80>) which is already presenting < TtGC7SwiftUI22SheetHostingControllerVS_7AnyView : 0x7f8fcbd310b0>.
我使用的大部分代码都是 Xcode 自己的样板代码,以及从网络上借来的常见模式。你能帮我调试一下吗?
为了重现,在 Xcode 12 中,使用 CoreData 创建一个新的 SwiftUI iOS 应用程序。将 ContentView.swift 替换为:
import SwiftUI
import CoreData
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
animation: .default)
private var items: FetchedResults<Item>
@State var showingSheet: Bool = false
var body: some View {
NavigationView {
List {
//Text("static text")
ForEach(items) { item in
Text("Item at \(item.timestamp!, formatter: itemFormatter)")
}
.onDelete(perform: deleteItems)
}
.navigationTitle("List of items")
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: {
showingSheet = true
}) {
Text("Open sheet")
}
.sheet(isPresented: $showingSheet) {
MySheetView(isPresented: $showingSheet)
.environment(\.managedObjectContext, viewContext)
}
}
}
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { items[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
private let itemFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .medium
return formatter
}()
创建一个新的 MySheetView.swift:
struct MySheetView: View {
@Environment(\.managedObjectContext) private var viewContext
@Binding var isPresented: Bool
var body: some View {
NavigationView {
Form {
Button(action: {
self.isPresented = false
}) {
Text("Dismiss this sheet")
}
Button(action: {
let newItem = Item(context: viewContext)
newItem.timestamp = Date()
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}) {
Text("Add Item")
}
}
}
}
}
运行时,如果点击“打开工作表”,然后可以点击“关闭此工作表”,它就可以工作了。但是,如果您点击“打开工作表”,然后点击“添加项目”,则会打印错误并且“关闭此工作表”按钮停止工作。(您仍然可以向下滑动以关闭工作表。)
我也尝试了presentationmode.wrappedvalue.dismiss() 方法,但没有成功。
我发现,如果您在主视图上注释掉 ForEach 循环并取消注释文本(“静态文本”),那么在工作表上添加项目不再打印出错误或中断工作表的解散。所以这个问题在某种程度上与在主工作表上显示数据有关。但显然我确实需要实际显示数据,这似乎是一种非常常见和基本的模式。我做错了吗?
解决方案
您.sheet
被放置在 ToolbarItem 上。只需更改它NavigationView
,它就可以工作。
这是 ContentView 的主体
var body: some View {
NavigationView {
List {
//Text("static text")
ForEach(items, id:\.self) { item in
Text("Item at \(item.timestamp!, formatter: itemFormatter)")
}
.onDelete(perform: deleteItems)
}
.navigationTitle("List of items")
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: {
showingSheet = true
}) {
Text("Open sheet")
}
}
}
.sheet(isPresented: $showingSheet) {
MySheetView(isPresented: $showingSheet)
.environment(\.managedObjectContext, viewContext)
}
}
}
推荐阅读
- flutter - GridView.builder 和 Image.network 性能问题
- php - 在 MariaDB 中(通过 PHP)更改列名时,如何为列提供当前数据定义?
- powershell - 如何根据 XML 属性捕捉 XML 的值
- c++ - 部分模板专业化
- vb.net - 在 VB.NET 中使用 Google YouTube Data API 获取 YouTube 频道数据
- r - 无论文档边界如何,都可以有效地计算大型语料库中的词频
- c++ - 在 Rcpp (Armadillo) 函数中使用数字序列作为默认参数
- mysql - 查询此 Department-Employee 表以获取具有确切员工的部门的最佳方法是什么?
- arrays - 没有malloc的动态数组?
- angular - 单行 2 个离子项目,右侧第 3 个