SwiftUI CoreData 过滤列表删除意外失败
Posted
技术标签:
【中文标题】SwiftUI CoreData 过滤列表删除意外失败【英文标题】:SwiftUI CoreData Filtered List Deletion Fails Unpredictably 【发布时间】:2020-10-12 21:41:27 【问题描述】:我正在努力使用具有 SwiftUI 生命周期的 SwiftUI 应用程序,在该应用程序中,我创建了一个相当标准的 Core Data 列表并添加了一个搜索字段来过滤列表。两种观点——一种带有谓词,一种没有。未经过滤的列表生成按预期工作,包括滑动删除。过滤后的列表会适当地显示过滤后的列表,但在滑动删除时,我会得到完全不可预测的结果。有时该项目会消失,有时它会重新出现在列表中,有时会删除错误的项目。我无法辨别任何模式。
这是视图:
struct MyFilteredListView: View
@Environment(\.managedObjectContext) private var viewContext
@Environment(\.horizontalSizeClass) var sizeClass
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \InvItem.name, ascending: true)],
animation: .default) private var invItems: FetchedResults<InvItem>
var fetchRequest: FetchRequest<InvItem>
init(filter: String)
//there are actually a bunch of string fields included - just listed two here
fetchRequest = FetchRequest<InvItem>(entity: InvItem.entity(), sortDescriptors: [], predicate: NSPredicate(format: "category1 CONTAINS[c] %@ || name CONTAINS[c] %@ ", filter, filter))
var body: some View
let sc = (sizeClass == .compact)
return List
ForEach(fetchRequest.wrappedValue, id: \.self) item in
NavigationLink(destination: InvItemDetailView(invItem: item))
InvItemRowView(invItem: item)
.frame(minWidth: 0, maxWidth: .infinity)
.frame(height: sc ? 100 : 200)
.padding(.leading, 10)
//link
.onDelete(perform: deleteInvItems)
//list
private func deleteInvItems(offsets: IndexSet)
withAnimation
offsets.map invItems[$0] .forEach(viewContext.delete)
do
try viewContext.save()
catch
// Replace this - raise an alert
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
Core Data 非常标准:
class InvItem: NSManagedObject, Identifiable
extension InvItem
@NSManaged var id: UUID
@NSManaged var category1: String?
@NSManaged var name: String
//bunch more attributes
public var wrappedCategory1: String
category1 ?? "No category1"
//other wrapped items
//extension inv item
extension InvItem
static func getAllInvItems() -> NSFetchRequest<InvItem>
let request: NSFetchRequest<InvItem> = InvItem.fetchRequest() as! NSFetchRequest<InvItem>
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
request.sortDescriptors = [sortDescriptor]
return request
//extension
我猜我不理解 deleteInvItems(offsets: IndexSet) 中的偏移行为,但是 我无法找到任何关于此的内容。相同的代码在未过滤列表中按预期工作。
任何指导将不胜感激。 Xcode 版本 12.2 beta (12B5018i) ios 14
第一次编辑: 我弄清楚了模式。显然 IndexSet 指的是整个实体,而不是过滤的项目。例如,未过滤列表有 10 个项目,过滤列表有 3 个项目。当我删除过滤列表中的第三项时,结果是删除未过滤列表中的第三项,因此除非这两者相同,否则第三项会重新出现在过滤列表中,并且未过滤列表中的第三项被删除来自核心数据。如果我再次删除过滤列表中的第三项,则原始列表中的第四项将被删除(因为第三项已经消失)。 所以问题就变成了 - 我如何获得对我想要的对象的引用 删除 - IndexSet 不起作用。
【问题讨论】:
【参考方案1】:这可能是因为您的ForEach
正在使用wrappedValue
,它可能会或可能不会更新。
https://developer.apple.com/documentation/swiftui/binding/wrappedvalue
我建议您查看创建新项目时提供的代码(您正在使用其中的一些),以便您可以调整并获得更准确的数据。
ForEach(items) item in
此外,在删除时,您将fetchRequest
中的offset
和invItems
中的项目混合在一起,只使用一个。
如果您希望能够动态过滤列表,我最好使用包裹在 ObservedObject
中的 FetchedResultsController
https://www.youtube.com/watch?v=-U-4Zon6dbE
【讨论】:
我明白你对包装价值的看法。这是我能找到的能够动态更新搜索值的唯一方法。 FRC 的想法看起来很有希望 - 我会尝试的。 对于其他人:上述想法并没有完全解决我的问题。我去了老学校 - 对过滤后的项目进行了获取请求,创建了一个数组,读取要删除的对象的 id(在我的情况下为 UUID),获取该对象并将其删除。以上是关于SwiftUI CoreData 过滤列表删除意外失败的主要内容,如果未能解决你的问题,请参考以下文章
过滤后的 SwiftUI CoreData 列表中的 Sum 属性
SwiftUI - 如何在 CoreData 中删除实体中的行
删除coredata列表项时SwiftUI App崩溃EXC_BAD_ACCESS错误
SwiftUI:如何将 CoreData 与动态过滤器相加?