【问题标题】:Crash when deleting data with relation in RealmSwift在 RealmSwift 中删除具有关系的数据时崩溃
【发布时间】:2020-04-08 15:24:41
【问题描述】:

我正在使用 RealmSwift 创建一个应用程序。

以下实现在删除相关数据时崩溃。

仅删除“UnderlayerItem”后,它成功了。 删除 UnderlayerItem 和删除 Item 时崩溃。

错误是:

线程 1:异常:“RLMArray 已失效或对象 包含它已被删除。”

如何删除而不崩溃?

struct ListView: View {
    @ObservedObject private var fetcher = Fetcher()
    @State private var title = ""

    var body: some View {
        NavigationView {
            VStack {
                TextField("add", text: $title) {
                    let item = Item()
                    item.title = self.title
                    let realm = try! Realm()
                    try! realm.write {
                        realm.add(item)
                    }
                    self.title = ""
                }

                ForEach(self.fetcher.items) { (item: Item) in
                    NavigationLink(destination: DetailView(item: item, id: item.id)) {
                        Text(item.title)
                    }
                }
            }
        }
    }
}

struct DetailView: View {
    var item: Item
    var id: String
    @State private var title = ""
    @ObservedObject private var fetcher = Fetcher()
    @Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>

    var body: some View {
        VStack {
            TextField("add", text: $title) {
                let realm = try! Realm()

                if let item = realm.objects(Item.self).filter("id == '\(self.id)'").first {
                    try! realm.write() {
                        let underlayerItem = UnderlayerItem()
                        underlayerItem.title = self.title
                        item.underlayerItems.append(underlayerItem)
                    }
                }
                self.title = ""
            }

            ForEach(self.item.underlayerItems) { (underlayerItems: UnderlayerItem) in
                Text(underlayerItems.title)
            }

            Button(action: {
                self.presentationMode.wrappedValue.dismiss()
                self.fetcher.delete(id: self.id)
            }) {
                Text("Delete")
            }
        }
    }
}

class Fetcher: ObservableObject {
    var realm = try! Realm()
    var objectWillChange: ObservableObjectPublisher = .init()
    private(set) var items: Results<Item>
    private var notificationTokens: [NotificationToken] = []

    init() {
        items = realm.objects(Item.self)

        notificationTokens.append(items.observe { _ in
            self.objectWillChange.send()
        })
    }

    func delete(id: String) {
        guard let item = realm.objects(Item.self).filter("id == '\(id)'").first else { return }

        try! realm.write() {
            for underlayerItem in item.underlayerItems {
                realm.delete(realm.objects(UnderlayerItem.self).filter("id == '\(underlayerItem.id)'").first!)
            }
        }

        try! realm.write() {
            realm.delete(item)
        }
    }
}

class Item: Object, Identifiable {
    @objc dynamic var id = NSUUID().uuidString
    @objc dynamic var title = ""
    @objc dynamic var createdAt = NSDate()

    let underlayerItems: List<UnderlayerItem> = List<UnderlayerItem>()

    override static func primaryKey() -> String? {
        return "id"
    }
}

class UnderlayerItem: Object, Identifiable {
    @objc dynamic var id = NSUUID().uuidString
    @objc dynamic var title = ""
    @objc dynamic var createdAt = NSDate()

    override static func primaryKey() -> String? {
        return "id"
    }
}

【问题讨论】:

  • 澄清一下,您的目标是删除列表中的所有项目吗?例如Item 有一个 UnderlayerItem 对象列表,您希望将它们删除吗?哪条线路崩溃了?

标签: swift realm swiftui


【解决方案1】:

您无需遍历列表中的对象即可删除它们。就这样做

try! realm.write() {
   realm.delete(item.underlayerItems)
}

我认为它崩溃是因为您试图访问已删除的项目

self.item.underlayerItems

【讨论】:

  • 谢谢!我不知道如何防止删除后访问“self.item.underlayerItems”...
  • @Ika self.item 似乎引用了已删除的项目。因此,您需要将其设置为 nil 或在删除后将其删除。澄清一下,Realm Results 是与其持有的领域对象的实时连接,如果您从领域中删除一个对象,它也将从结果对象中删除。但是,如果您创建对 self.item 等领域对象的单独引用并将其从领域中删除,则 self.item 将指向该已删除项目。
  • 谢谢!我用“if(!Self.isDeleted)”将“self.item.underlayerItems”的 ForEach 括起来。当我单击删除按钮时,我设置了“self.isDeleted = true”。然后你被删除而没有崩溃!这样合适吗?
  • @Ika 这行得通。但是.. 我很好奇您为什么要遍历已删除的项目数组。
猜你喜欢
  • 2016-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多