You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI+Realm使用ConfirmationDialog删除时崩溃问题求助

问题:SwiftUI结合Realm使用ConfirmationDialog删除数据时崩溃

Sheet中执行删除操作正常,但通过ConfirmationDialog删除数据时,数据库中数据已成功删除,但应用会崩溃。以下是最小可复现示例:

入口代码

import SwiftUI

@main
struct ForTestApp: App {
    @StateObject private var store = SpaceStore()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(store)
        }
    }
}

ContentView代码

import SwiftUI
import RealmSwift

struct ContentView: View {
    @EnvironmentObject var store: SpaceStore
    
    var body: some View {
        Button("Add") {
            for id in 0...5 { SpaceStore.add(by: "tag: "+id.formatted()) }
        }
        Divider()
        if let spaces = store.spaces {
            ForEach(spaces) { space in
                RowView(space: space)
            }
        }
    }
}

#Preview {
    ContentView()
        .environmentObject(SpaceStore())
}

RowView代码

import SwiftUI

struct RowView: View {
    let space: Space
    @State private var ifShowDialog = false
    @State private var ifShowSheet = false
    
    var body: some View {
        HStack {
            Text(space.name)
            Button("sheet") {
                ifShowSheet.toggle()
            }
            .sheet(isPresented: $ifShowSheet) {
                Button("Delete") {
                    SpaceStore.delete(space)
                }
                Button("ConfirmationDialogDelete") {
                    ifShowDialog.toggle()
                }
                .confirmationDialog("", isPresented: $ifShowDialog) {
                    Button("Delete", role: .destructive) {
                        SpaceStore.delete(space)
                    }
                }
            }
        }
    }
}

Model代码

import RealmSwift

class Space: Object, Identifiable {
    @Persisted(primaryKey: true) var id: ObjectId
    @Persisted var name: String = ""
    
    convenience init(name: String) {
        self.init()
        self.name = name
    }
}

ViewModel代码

import Foundation
import RealmSwift
class SpaceStore: ObservableObject {
    @Published var spaces: Results<Space>?
    
    static let realm = try! Realm()
    private var realmToken: NotificationToken?
    
    init() {
        let results = SpaceStore.realm.objects(Space.self)
        realmToken = results.observe { _ in
            self.spaces = results
        }
    }
    
    static func add(by name: String) {
        let space = Space(name: name)
        try! SpaceStore.realm.write {
            SpaceStore.realm.add(space)
        }
    }
    
    static func delete(_ space: Space) {
        try! SpaceStore.realm.write {
            SpaceStore.realm.delete(space)
        }
    }
}

崩溃原因

删除Realm对象后,该对象会被标记为isInvalidated = true,此时任何对该对象属性的访问都会触发崩溃。在ConfirmationDialog的场景中:

  1. 删除操作完成后,Realm的实时Results会更新,ContentView的ForEach会自动移除对应的RowView
  2. 但RowView内部的ifShowDialog和ifShowSheet状态仍为true,导致ConfirmationDialog和Sheet的视图仍试图引用已失效的space对象
  3. 而Sheet直接删除的场景中,RowView被移除后,Sheet的isPresented绑定的状态随之销毁,Sheet自动关闭,不会触发无效对象访问

解决方案

方案1:删除后立即关闭弹窗和Sheet

修改RowView中的删除逻辑,在删除后手动重置状态,切断对失效对象的引用:

// RowView中ConfirmationDialog的Delete按钮修改为:
Button("Delete", role: .destructive) {
    SpaceStore.delete(space)
    // 关闭弹窗和Sheet
    ifShowDialog = false
    ifShowSheet = false
}

// Sheet中的Delete按钮也可以同步加上关闭逻辑:
Button("Delete") {
    SpaceStore.delete(space)
    ifShowSheet = false
}

方案2:通过对象ID执行删除操作(更安全)

避免直接持有Realm对象,改用对象ID来执行删除,即使对象被删除也不会触发无效引用:

  1. 修改SpaceStore的delete方法:
static func delete(by id: ObjectId) {
    guard let space = realm.object(ofType: Space.self, forPrimaryKey: id) else { return }
    try! realm.write {
        realm.delete(space)
    }
}
  1. 修改RowView中的调用:
// Sheet中的Delete按钮
Button("Delete") {
    SpaceStore.delete(by: space.id)
    ifShowSheet = false
}

// ConfirmationDialog中的Delete按钮
Button("Delete", role: .destructive) {
    SpaceStore.delete(by: space.id)
    ifShowDialog = false
    ifShowSheet = false
}

这两种方案都能解决崩溃问题,方案2更符合Realm的最佳实践,避免持有可能失效的对象引用。


内容的提问来源于stack exchange,提问作者hi-mango

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 16:27:52