【问题标题】:Crash when delete a record from coredata in SwiftUI在 SwiftUI 中从 coredata 中删除记录时崩溃
【发布时间】:2020-06-21 14:02:44
【问题描述】:

我为 coredata 中的音频项目制作了一个列表。删除后,crash 报“EXC_BREAKPOINT (code=1, subcode=0x1b8fb693c)”,为什么?

使用时

ForEach(items, id: \.self)

,它的工作原理。但 My Audio 具有 id 属性并遵循 Identifiable 协议。

更新:我发现添加 if{} 子句可以修复崩溃,但为什么呢? “静态 UUID.unconditionallyBridgeFromObjectiveC(:) ()”处的断点。

struct Test1View: View {
    @Environment(\.managedObjectContext) var context
    @FetchRequest(fetchRequest: Audio.fetchAllAudios()) var items: FetchedResults<Audio>
    var body: some View {
        List {
            ForEach(items) { item in
                if true { // <- this if clause fix crash, but why?
                    HStack {
                        Text("\(item.name)")
                    }
                }
            }.onDelete(perform: { indexSet in
                let index = indexSet.first!
                let item = self.items[index]
                self.context.delete(item)
                try? self.context.save()
            })
        }
    }
}

代码如下:

class Audio: NSManagedObject, Identifiable {
    @NSManaged public var id: UUID
    @NSManaged public var name: String
    @NSManaged public var createAt: Date
}

struct Test1View: View {
    @Environment(\.managedObjectContext) var context
    var fetchRequest: FetchRequest<Audio> = FetchRequest<Audio>(entity: Audio.entity(), sortDescriptors: [NSSortDescriptor(key: "createAt", ascending: false)])
    var items: FetchedResults<Audio> { fetchRequest.wrappedValue }
    var body: some View {
        List {
            ForEach(items) { item in
                HStack {
                    Text("\(item.name)")
                }
            }.onDelete(perform: { indexSet in
                let index = indexSet.first!
                let item = self.items[index]
                self.context.delete(item)
                try? self.context.save()
            })
        }
    }
}

【问题讨论】:

    标签: core-data swiftui


    【解决方案1】:

    我和你有同样的问题。

    使用您自己的id 属性将其设置为Identifiable 可能是个坏主意,因为Core Data 在删除对象时将所有属性设置为nil,即使您在Swift 中声明它的方式不同核心数据类。 删除实体时,id 属性无效,对象 .isFault 属性设置为 true,但 SwiftUI ForEach 仍然持有对此 ID 对象(=您的 UUID)的一些引用,以便能够计算列表的“之前”和“之后”状态,并以某种方式尝试访问它,导致崩溃。

    因此有以下建议:

    1. 保护详细视图(在ForEach 循环中,通过检查isFault
    if entity.isFault {
        EmptyView()
    }
    else {
        // your regular view body
    }
    
    1. 期望您的 id 属性为 nil,方法是在您的核心数据模型中将其相应地定义为可选
    @NSManaged public var id: UUID?
    

    不依赖 SwiftUI ForEach 循环中的Identifiable 协议:

    ForEach(entities, id: \.self) { entity in ... }
    

    ForEach(entities, id: \.objectID) { entity in ... }
    

    结论:您确实不需要将所有 CoreData 属性都设为 Swift Optionals。在ForEach 循环中引用的id 属性能够优雅地处理删除(=将其值设置为nil),这一点非常重要。

    【讨论】:

      【解决方案2】:

      周末我也遇到了同样的问题。看起来 SwiftUI 想要解开我从 CoreData 读取的值,并且由于该值已经被删除,它会崩溃。

      在我的情况下,我确实通过对我从 CoreData 使用的所有值进行 nil 合并来解决它。

      您可以尝试使用

      为您的 item.name 提供默认值
      ForEach(items) { item in
                  HStack {
                      Text("\(item.name ?? "")")
                  }
              }
      

      【讨论】:

      • 我有另一个代码,和这个示例代码一样,可以正常工作。我很困惑。 ForEach(items, id: \.self) 将修复此代码。如果这真的是 SwiftUI 中的 CoreData 问题,那就太糟糕了。我想知道我是否在这段代码中犯了一些错误。
      • 问题是UUID._unconditionallyBridgeFromObjectiveC,无指针。添加 if true {} 子句将修复崩溃,但为什么呢? ForEach(items) { item in if true { HStack { Text("\(item.name)") } } }
      【解决方案3】:

      我找到了崩溃的原因,必须提供可选的,因为OC/swift对象转换:

      转换

      class Audio: NSManagedObject, Identifiable {
          @NSManaged public var id: UUID
          @NSManaged public var name: String
          @NSManaged public var createAt: Date
      }
      

      class Audio: NSManagedObject, Identifiable {
          @NSManaged public var id: UUID?
          @NSManaged public var name: String?
          @NSManaged public var createAt: Date?
      }
      

      【讨论】:

      • 你救了我!我花了 30 分钟处理这个错误,这解决了:)
      • 谢谢!对我来说,将 ID 设置为可选就足够了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-18
      • 1970-01-01
      • 1970-01-01
      • 2015-10-22
      • 1970-01-01
      相关资源
      最近更新 更多