listview - SwiftUI 列表在删除后继续显示核心数据项
问题描述
我正在探索 SwiftUI,但遇到了一个问题。我有一个使用 Core Data 保存的歌手列表
let singer1 = Singer(context: viewContext)
singer1.firstName = "Taylor"
singer1.lastName = "Swift"
let singer2 = Singer(context: viewContext)
singer2.firstName = "Ed"
singer2.lastName = "Sheeran"
let singer3 = Singer(context: viewContext)
singer3.firstName = "Adele"
singer3.lastName = "Adkins"
try? viewContext.save()
我创建了另一个视图来填充歌手列表。
struct ListOfSingers<T: NSManagedObject, Content: View>: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest<T> var singers: FetchedResults<T>
let content: (T) -> Content
init(filterKey: String, filterValue: String, @ViewBuilder content: @escaping (T) -> Content) {
_singers = FetchRequest<T>(entity: T.entity(), sortDescriptors: [], predicate: NSPredicate(format: "%K BEGINSWITH %@", filterKey, filterValue))
self.content = content
}
var body: some View {
List {
ForEach(singers, id: \.self) {
content($0)
}.onDelete(perform: deleteSinger)
}
}
func deleteSinger(at offsets: IndexSet) {
withAnimation {
offsets.map { singers[$0] }.forEach(viewContext.delete)
try? viewContext.save()
}
}
}
我使用谓词将它们分类为 2 个列表。我无法解决的问题是,当我使用谓词“S”并删除列表中的对象,然后返回谓词“A”并删除该列表中的歌手时,即使我检查了歌手,我仍然有歌手显示在那里' 数组,它说它是空的。我也可以与这个“幽灵”对象交互,但是如果我尝试删除这个对象应用程序崩溃,因为现在它知道数组是空的并且有这样一个对象要删除。
这是我的内容视图:
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@State var lastNameFilter = "A"
var body: some View {
NavigationView {
VStack {
ListOfSingers(filterKey: "lastName", filterValue: lastNameFilter) { (singer: Singer) in
Text("\(singer.wrappedName) \(singer.wrappedLastName)")
.onAppear { print( "\(singer.wrappedName) \(singer.wrappedLastName)" )}
}
Button("Add Singers") {
let singer1 = Singer(context: viewContext)
singer1.firstName = "Taylor"
singer1.lastName = "Swift"
let singer2 = Singer(context: viewContext)
singer2.firstName = "Ed"
singer2.lastName = "Sheeran"
let singer3 = Singer(context: viewContext)
singer3.firstName = "Adele"
singer3.lastName = "Adkins"
try? viewContext.save()
}
.frame(width: 280, height: 50)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
.padding()
HStack {
Button("Sort by A") {
withAnimation {
lastNameFilter = "A"
}
}
.frame(width: 130, height: 50)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Spacer()
Button("Sort by S") {
withAnimation {
lastNameFilter = "S"
}
}
.frame(width: 130, height: 50)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
.padding()
}
.navigationTitle("Singers") }}}
解决方案
问题是由于某种原因 ListOfSingers 结构被调用了两次。即使我从 Core Data 中删除了最后一位歌手,渲染时间也比重新索引 Core Data 更快。所以我最终得到了一个“幽灵视图”,它是在我的项目从核心数据中完全删除之前呈现的。当我尝试删除 Ghost 视图时,我遇到了一个不存在的数组。它总是导致应用程序崩溃。
解决方案是添加一个函数,在删除触发后立即检查 Core Data 中是否有任何项目。
在主视图中创建
@State var noMoreSingers = false
以检查应该呈现哪个视图并将这个条件添加到 VStack 以明确告诉应该呈现哪个视图:VStack { if !noMoreSingers { ListOfSingers(filterKey: "lastName", filterValue: lastNameFilter) { (singer: Singer) in Text("\(singer.wrappedName) \(singer.wrappedLastName)") } } else { Spacer() }
添加一个
@Binding var noMoreSingers: Bool
toListOfSingers
以便能够在 Core Data 中没有更多项目时告诉主视图向 Persistanse Controller 添加函数以获取所有项目:
func getAllSingers() -> [Singer] { let request: NSFetchRequest<Singer> = Singer.fetchRequest() do { return try container.viewContext.fetch(request) } catch { fatalError("Error Fetching Users") } }
将函数添加到 ListOfSingers 以触发
getAllSingers
并检查检索到的数组是否为空:func checkIfSingersAreEmpty() { let checkSingers = PersistenceController.shared.getAllSingers() if checkSingers.isEmpty { noMoreSingers = true } }
现在一切正常!
推荐阅读
- node.js - 获取 Node.js + Express REST API 来更新 mongoDB
- search - 如何配置 Fuse.js 搜索结果以匹配单个单词?
- python - Coinpaprika 达到最大请求限制错误
- mysql - 加载 infile 命令从第一个字符中删除 0
- android - 我的 (android) 设备进入睡眠状态后,我的网站的音频播放器将暂停
- reactjs - 在反应引导下拉按钮中显示第一个选定的项目
- c++ - 为什么小于等于运算符在 C++ 中对两个 ```double``` 值显示意外行为?
- node.js - 如何将 Flutter 与 NodeJS 后端连接起来
- azure - 有没有办法为 Azure AD 中的一些来宾帐户设置基于 OTP 的身份验证?
- swift - Swift 如何知道是否选择了我的细分项目之一?