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

Swift 6中Realm数据库定义与对象处理问题求助

问题分析与解决方案

1. 修复Realm关联对象定义错误

你遇到的EXC_BAD_ACCESS核心原因是Pedido类的cargas列表未添加@Persisted注解——Realm Swift 10+版本中,所有需要持久化的属性(包括List类型)必须用@Persisted标记,否则Realm无法识别和管理这个关联集合,访问时会直接崩溃。

修正后的Pedido类:

import Foundation
import RealmSwift

class Pedido: Object{
  @Persisted(primaryKey: true) var _id: Int32
  @Persisted var cargas = List<Carga>() // 必须添加@Persisted

  convenience init(_id: Int32, listCargas: List<Carga>){
    self.init()
    self._id = _id
    // 用append而非直接赋值,避免绕过Realm的对象跟踪机制
    self.cargas.append(objectsIn: listCargas)
  }
}

2. 完善RealmManager的核心实现

你的RealmManager缺少关键的初始化配置、查询、写入方法,且错误处理不完整,这会导致数据库操作出现隐性问题。以下是完整实现:

import RealmSwift

// 先补充DBConfig的结构定义(根据你的需求调整)
struct DBConfig {
    var fileURL: URL
    var readOnly: Bool = false
}

class RealmManager: RealmDB {
    internal var config: DBConfig
    private var _database: Realm?

    init(configuration: DBConfig){
        self.config = configuration
    }

    internal var database: Realm? {
        get{
            if _database == nil {
                do {
                    try configure()
                } catch let error {
                    print("Realm初始化失败: \(error.localizedDescription)")
                }
            }
            return _database
        }
    }

    private func configure() throws {
        var realmConfig = Realm.Configuration(
            fileURL: config.fileURL,
            readOnly: config.readOnly,
            schemaVersion: 1 // 后续修改对象结构时需同步升级版本
        )
        // 设置全局默认配置(可选,方便其他地方直接调用Realm())
        Realm.Configuration.defaultConfiguration = realmConfig
        _database = try Realm(configuration: realmConfig)
    }

    func get<T: Object>(type: T.Type) throws -> Results<T> {
        guard let realm = database else {
            throw NSError(domain: "RealmError", code: -1, userInfo: [NSLocalizedDescriptionKey: "数据库未初始化"])
        }
        return realm.objects(type)
    }

    func get<T: Object>(type: T.Type, query: ((Query<T>) -> Query<Bool>)) throws -> Results<T> {
        guard let realm = database else {
            throw NSError(domain: "RealmError", code: -1, userInfo: [NSLocalizedDescriptionKey: "数据库未初始化"])
        }
        return realm.objects(type).where(query)
    }

    func save<S: Sequence>(objects: S) throws where S.Iterator.Element: Object {
        guard let realm = database else {
            throw NSError(domain: "RealmError", code: -1, userInfo: [NSLocalizedDescriptionKey: "数据库未初始化"])
        }
        try realm.write {
            // .modified策略:存在则更新,不存在则添加
            realm.add(objects, update: .modified)
        }
    }
}

3. ViewController中正确操作关联对象

在ViewController中使用Realm时,必须遵守线程绑定规则(Realm对象/Results/List不能跨线程访问),并通过监听机制同步UI:

import UIKit
import RealmSwift

class PedidoViewController: UIViewController {
    private var realmManager: RealmManager!
    private var pedidos: Results<Pedido>?
    private var notificationToken: NotificationToken? // 监听数据变化的令牌

    override func viewDidLoad() {
        super.viewDidLoad()
        // 初始化RealmManager
        let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        let dbURL = documentsDir.appendingPathComponent("app.realm")
        let config = DBConfig(fileURL: dbURL)
        realmManager = RealmManager(configuration: config)

        // 示例:添加测试数据
        addTestData()
        // 查询并监听数据
        fetchAndObservePedidos()
    }

    private func addTestData() {
        do {
            let carga1 = Carga(_id: 1, idPedido: 1001, kilograms: 50.0)
            let carga2 = Carga(_id: 2, idPedido: 1001, kilograms: 30.0)
            let cargasList = List<Carga>()
            cargasList.append(carga1)
            cargasList.append(carga2)
            let pedido = Pedido(_id: 1001, listCargas: cargasList)
            try realmManager.save(objects: [pedido])
        } catch let error {
            print("保存数据失败: \(error.localizedDescription)")
        }
    }

    private func fetchAndObservePedidos() {
        do {
            pedidos = try realmManager.get(type: Pedido.self)
            // 监听数据变化,自动更新UI
            notificationToken = pedidos?.observe { [weak self] change in
                guard let self = self else { return }
                switch change {
                case .initial, .update:
                    self.updateUI()
                case .error(let error):
                    print("数据监听错误: \(error.localizedDescription)")
                }
            }
        } catch let error {
            print("查询数据失败: \(error.localizedDescription)")
        }
    }

    private func updateUI() {
        guard let firstPedido = pedidos?.first else { return }
        // 安全访问关联列表:先判断非空再取值
        if let firstCarga = firstPedido.cargas.first {
            print("第一个Carga重量: \(firstCarga.kilograms)")
            // 这里可以更新UI组件,比如:
            // weightLabel.text = "\(firstCarga.kilograms) kg"
        }
    }

    deinit {
        // 销毁监听令牌,避免内存泄漏
        notificationToken?.invalidate()
    }
}

4. 常见崩溃排查补充

  • 若仍出现EXC_BAD_ACCESS,检查是否跨线程访问Realm对象:Realm的所有实例、Results、List都是线程绑定的,后台线程获取的对象不能拿到主线程直接用,需在当前线程重新查询,或使用ThreadSafeReference传递对象。
  • 数据未持久化:确保所有写入操作都在try realm.write {}事务块中执行。
  • 初始化失败:若修改过对象结构,需同步升级schemaVersion并配置迁移块,否则会触发版本不匹配错误。

内容的提问来源于stack exchange,提问作者DMarMon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 13:17:22