SwiftUI 列表在删除后继续显示核心数据项
SwiftUI List Keeps Showing Core Data Items After They Were Deleted
我正在探索 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([=11=])
}.onDelete(perform: deleteSinger)
}
}
func deleteSinger(at offsets: IndexSet) {
withAnimation {
offsets.map { singers[[=11=]] }.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 View 时,我到达了一个不存在的数组。它总是会导致应用程序崩溃。
解决方案是添加一个函数,在删除启动后立即检查核心数据中是否有任何项目。
在主视图中创建 @State var noMoreSingers = false
以检查应呈现哪个视图并将此条件添加到 VStack 以明确告知应呈现哪个视图:
VStack {
if !noMoreSingers {
ListOfSingers(filterKey: "lastName", filterValue: lastNameFilter) { (singer: Singer) in
Text("\(singer.wrappedName) \(singer.wrappedLastName)")
} } else {
Spacer()
}
在 ListOfSingers
中添加一个 @Binding var noMoreSingers: Bool
以便在 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
}
}
现在一切正常!
我正在探索 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([=11=])
}.onDelete(perform: deleteSinger)
}
}
func deleteSinger(at offsets: IndexSet) {
withAnimation {
offsets.map { singers[[=11=]] }.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 View 时,我到达了一个不存在的数组。它总是会导致应用程序崩溃。
解决方案是添加一个函数,在删除启动后立即检查核心数据中是否有任何项目。
在主视图中创建
@State var noMoreSingers = false
以检查应呈现哪个视图并将此条件添加到 VStack 以明确告知应呈现哪个视图:VStack { if !noMoreSingers { ListOfSingers(filterKey: "lastName", filterValue: lastNameFilter) { (singer: Singer) in Text("\(singer.wrappedName) \(singer.wrappedLastName)") } } else { Spacer() }
在
ListOfSingers
中添加一个@Binding var noMoreSingers: Bool
以便在 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 } }
现在一切正常!