Ios SwiftUI核心数据无法从列表中删除多行
我有一个SwiftUI应用程序,具有完整的SwiftUI流和核心数据持久性。这是一个基本的问题 主控/细节风格,并按预期稳定工作。我想添加一个功能以允许 要选择和删除的多行。单行滑动以按预期删除作品 我从中得到了灵感:58910010然而,该示例使用了 struct items和我无法使用核心数据对象复制过程 基本上,显示编辑复选框和按钮切换的功能 功能按预期工作,但当我点击垃圾箱图标时,应用程序崩溃。有 控制台中没有任何信息,线程日志中也没有任何帮助 请参见以下deleteCards()中的注释1。如果我注释掉viewContext保存,则应用程序会这样做 不会崩溃,选定的卡将从列表中删除,但在重新启动时,这些卡将被删除 仍然存在。如果我将viewContext保存留在原位,应用程序将崩溃,但会继续运行 重新启动我看到所选项目不再存在 以下是一个简化版本:Ios SwiftUI核心数据无法从列表中删除多行,ios,core-data,swiftui,Ios,Core Data,Swiftui,我有一个SwiftUI应用程序,具有完整的SwiftUI流和核心数据持久性。这是一个基本的问题 主控/细节风格,并按预期稳定工作。我想添加一个功能以允许 要选择和删除的多行。单行滑动以按预期删除作品 我从中得到了灵感:58910010然而,该示例使用了 struct items和我无法使用核心数据对象复制过程 基本上,显示编辑复选框和按钮切换的功能 功能按预期工作,但当我点击垃圾箱图标时,应用程序崩溃。有 控制台中没有任何信息,线程日志中也没有任何帮助 请参见以下deleteCards()中的注
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Card.lastName, ascending: true)],
animation: .default)
private var cards: FetchedResults<Card>
@State var editMode: EditMode = .inactive
@State var selection = Set<UUID>()
var body: some View {
NavigationView {
List(selection: $selection) {
ForEach(cards) { card in
VStack(alignment: .leading) {
Text("\(card.wrappedFirstName) \(card.wrappedLastName)")
Text("\(card.wrappedComment)")
}
}
.onDelete(perform: deleteItems)
}
.navigationBarItems(
leading: editButton,
trailing:
HStack {
addDelButton
addExamplesButton
}
)
.environment(\.editMode, self.$editMode)
.navigationTitle("Cards")
}//nav
}//body
private var editButton: some View {
Button(action: {
self.editMode.toggle()
self.selection = Set<UUID>()
}) {
Text(self.editMode.title)
}
}//edit button
private var addDelButton: some View {
if editMode == .inactive {
return Button(action: addCard) {
Image(systemName: "plus")
}
} else {
return Button(action: deleteCards) {
Image(systemName: "trash")
}
}
}//add del button
private var addExamplesButton: some View {
Button(action: {
self.addExampleRecords()
}) {
Image(systemName: "gear")
}
}//add examples
private func deleteCards() {
for id in selection {
if let index = cards.lastIndex(where: { $0.id == id }) {
viewContext.delete(cards[index])
}
}
selection = Set<UUID>()
//Note 1: this crashed the app - but deletions happen
do {
try viewContext.save()
} catch {
// Replace this
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}//delete Cards
private func addCard() {
withAnimation {
let newCard = Card(context: viewContext)
newCard.id = UUID()
newCard.firstName = "NewFirstName"
newCard.lastName = "NewLastName"
newCard.creationDate = Date()
do {
try viewContext.save()
} catch {
// Replace this
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}//add card
private func addExampleRecords() {
let context = self.viewContext
for c in 0..<10 {
let nmo = Card(context: context)
nmo.id = UUID()
nmo.lastName = "ExLast \(c)"
nmo.firstName = "ExFirst \(c)"
nmo.comment = "ExComment \(c)"
nmo.creationDate = Date()
}
}//add example records
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { cards[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
// Replace this
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}//delete items
}//struct
extension EditMode {
var title: String {
self == .active ? "Done" : "Edit"
}
mutating func toggle() {
self = self == .active ? .inactive : .active
}
}// ext
struct ContentView:View{
@环境(\.managedObjectContext)私有变量viewContext
@获取请求(
SortDescriptor:[NSSortDescriptor(密钥路径:\Card.lastName,升序:true)],
动画:。默认设置)
私有var卡:获取结果
@状态变量editMode:editMode=.inactive
@State var selection=Set()
var body:一些观点{
导航视图{
列表(选择:$selection){
ForEach(cards){card in
VStack(对齐:。前导){
文本(\(card.wrappedFirstName)\(card.wrappedLastName))
文本(“\(card.wrappedComment)”)
}
}
.onDelete(执行:删除项)
}
.航海术语(
引导:编辑按钮,
尾随:
HStack{
addDelButton
addExamplesButton
}
)
.environment(\.editMode,self.$editMode)
.导航标题(“卡片”)
}//导航
}//身体
私有var编辑按钮:一些视图{
按钮(操作:{
self.editMode.toggle()
self.selection=Set()
}) {
文本(self.editMode.title)
}
}//编辑按钮
私有var addDelButton:一些视图{
如果editMode==.inactive{
返回按钮(操作:添加卡){
图像(系统名称:“plus”)
}
}否则{
返回按钮(操作:删除卡片){
图像(系统名称:“垃圾”)
}
}
}//添加删除按钮
私有变量addExamplesButton:一些视图{
按钮(操作:{
self.addExampleRecords()
}) {
图像(系统名称:“齿轮”)
}
}//添加示例
专用功能删除卡(){
用于选择中的id{
如果let index=cards.lastIndex(其中:{$0.id==id}){
viewContext.delete(卡片[索引])
}
}
选择=设置()
//注意1:这使应用程序崩溃-但会发生删除
做{
请尝试viewContext.save()
}抓住{
//替换这个
设nsError=错误为nsError
fatalError(“未解决的错误\(nsError),\(nsError.userInfo)”)
}
}//删除卡片
私人func addCard(){
动画片{
让newCard=Card(上下文:viewContext)
newCard.id=UUID()
newCard.firstName=“NewFirstName”
newCard.lastName=“NewLastName”
newCard.creationDate=日期()
做{
请尝试viewContext.save()
}抓住{
//替换这个
设nsError=错误为nsError
fatalError(“未解决的错误\(nsError),\(nsError.userInfo)”)
}
}
}//添加卡
私有函数addExampleRecords(){
让context=self.viewContext
对于0..NSFetchRequest中的c{
返回NSFetchRequest(entityName:“卡”)
}
@NSManaged公共变量id:UUID
@NSManaged public var firstName:字符串?
@NSManaged public var注释:字符串?
@NSManaged public var lastName:字符串?
@NSManaged public var creationDate:日期?
public var wrappedFirstName:String{
名字??“没有名字”
}
公共变量wrappedLastName:String{
姓氏??“没有姓氏”
}
public var wrappedComment:String{
评论??“无评论”
}
公共变量wrappedCreationDate:日期{
创建日期??日期()
}
}
分机卡:可识别{
}
任何指导都将不胜感激。Xcode 12.3 iOS 14.2我记得我已经看到过类似的报告,无法使用Xcode 12.1/iOS 14.1复制崩溃,因此这是一个新版本缺陷。您提醒我在另一个应用程序中发现的问题。当您有核心数据手动创建属性文件时,它将标记为optionals(核心数据类型,不是Swift)如果更改,有时会中断流程。请注意,上面我已从UUID中删除了?。纠正了这一点,应用程序不再崩溃,但所选项目不会被删除。乍一看,选择行似乎不会将该对象添加到选择集中。有什么想法吗?
extension Card {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Card> {
return NSFetchRequest<Card>(entityName: "Card")
}
@NSManaged public var id: UUID
@NSManaged public var firstName: String?
@NSManaged public var comment: String?
@NSManaged public var lastName: String?
@NSManaged public var creationDate: Date?
public var wrappedFirstName: String {
firstName ?? "no first name"
}
public var wrappedLastName: String {
lastName ?? "no last name"
}
public var wrappedComment: String {
comment ?? "no comment"
}
public var wrappedCreationDate: Date {
creationDate ?? Date()
}
}
extension Card : Identifiable {
}