我正在使用 Swift 和 RealmSwift 构建我的小型应用程序,但在尝试使其工作时遇到多个错误。我得到的错误主要来自尝试从数据库读取对象,因为写入它们有时似乎有效。我之前问过一个问题,该问题通过设置领域对象的方法得到了回答,但现在我收到此 EXC_BAD_ACCESS 错误。让我们从我的 RealmManager 类开始,我在其中创建 Realm 实例。
import RealmSwift
import Foundation
class RealmManager {
private var configured: Bool
private var init(){
self.configured = false
}
static let shared = RealmManager()
lazy var realm: Realm = {
if !self.configured {
var config = Realm.Configuration.defaultConfiguration
let realm = try! Realm(configuration: config)
} else {
let realm = try! Realm()
}
return realm
}
func configure() throws {
let dbName = "MyApp.realm"
var dbConf = Realm.Configuration()
guard let url = dbConf.fileURL?.deletingLastPathComponent().appendingLastPathComponent(dbName) else {
throw DBError.databaseNameError
}
dbConf.fileURL = url
dbConf.readOnly = false
dbConf.schemaVersion = 1
do {
self.realm = try Realm(configuration: dbConf)
self.configured = true
} catch {
throw DBError.configurationError
}
}
然后我从 AppDelegate 类中调用该类:
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow
var realmM: Realm!
var pushToken: String = ""
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions : [UIApplication.LaunchOptionsKey: Any]?)-> Bool {
self.realmM = openRealm()
return true
}
private func openRealm() -> Realm {
do {
try RealmManager.shared.configure()
} catch {
print("Didnt configure Realm")
}
let realm = RealmManager.shared.realm
return realm
}
}
现在这就是我声明 3 个对象的方式,其中我收到了 EXC_BAD_ACCESS 错误:
import Foundation
import RealmSwift
class Carga: Object{
@Persisted(primaryKey: true) var idCarga : Int32
@Persisted var idPedido : Int32
@Persisted var units : Int32
@Persisted var packages : Int32
@Persisted var kilograms : Double
convenience init(_id: Int32, idPedido: Int32, uds: Int32, pkgs: Int32, kgs: Double) {
self.init()
self.idCarga = _id
self.idPedido = idPedido
self.units = uds
self.packages = pkgs
self.kilograms = kgs
}
}
class Pedido : Object{
@Persisted(primaryKey: true) var idPedido : Int32
@Persisted var idLugar : Int32
@Persisted var cargas = RealmSwift.List<Carga>() --> Thread 1: EXC_BAD_ACCESS (code=1,adress=0x0)
convenience init(_id: Int32, idLugar: Int32, listCargas: RealmSwift.List<Carga>) {
self.init()
self.idPedido = _id
self.idLugar = idLugar
self.cargas = listCargas
}
}
class Lugar : Object{
@Persisted(primaryKey: true) var idLugar : Int32
@Persisted var name : String
@Persisted var pedidos = RealmSwift.List<Pedido>() --> Thread 1 :EXC_BAD_ACCESS (code=1,adress=0x0)
convenience init(_id: Int32, name: String, listPedidos: RealmSwift.List<Pedido>) {
self.init()
self.idLugar = _id
self.name = name
self.pedidos = listPedidos
}
}
1-来自 RealmManager
self.realm = 尝试 Realm(配置:dbConf)
2-来自领域类
Realm.init()
3-RLMObjectSchema 类属性
获取属性(_:)
4-从对象初始化
Pedido.init()
Carga.init()
5- 从对象属性
@Persisted var cargas = RealmSwift.List()
@Persisted var pedidos = RealmSwift.List()
请勿编译此代码块。它只是 Thread1 在创建 Realm 实例时遵循的路径以及错误发生位置的表示。
我相信错误在于 Realm 的配置方式以及调用它的时间(AppDelegate?),而不是对象本身。
您似乎正在尝试创建一个在整个应用程序中持续存在的领域变量,这通常不是最佳实践。 Realm 不是线程安全的,对象和应用程序函数可以在不同的线程上运行;这会导致您看到的错误类型。
最佳实践是在需要时实例化 Realm 对象,或者按照下面的示例通过单例模式实例化。经验法则是,最好按需创建 Realm 实例,而不是提前抢先创建实例并保留它
调用Realm(configuration:)时,Realm本身会在内部进行缓存 该对象并将在每次后续调用时返回相同的对象。 该对象保留在缓存中,直到它被自动释放池 创建于已耗尽。 ——来自这个答案
我将使用问题中三个对象(复制和粘贴)的代码(请参阅此答案的底部)
然后,我将采用对一个单独问题的回答中的一些代码并对其进行修改,以将Realm文件写入我的Mac桌面(iOS功能类似)。您可以将 URL 指向适合您的用例的任何位置。这个
RealmService
是一个单例,应该放置在任何其他类之外。
class RealmService {
private init() {}
static let shared = RealmService()
lazy var realm: Realm = {
//modify below to be your iOS URL/path
let manager = FileManager()
let homeURL = manager.homeDirectoryForCurrentUser
let desktopURL = homeURL.appendingPathComponent("Desktop")
let pathToThisRealmFile = desktopURL.appendingPathComponent("desktopRealm.realm")
//modify above to be your iOS URL/path
var config = Realm.Configuration.defaultConfiguration
config.fileURL = pathToThisRealmFile
let realm = try! Realm.init(configuration: config)
return realm
}()
}
请注意,我没有从我的 AppDelegate 调用任何代码,因为没有理由这样做。 RealmService 仅在与 Realm 交互时才需要引用。请注意,此代码适用于本地领域;同步领域可以/应该以不同的方式处理。
然后是实例化和写入三个对象的代码;卡尔加、佩迪多和卢加尔。我在 UI 中添加了一个按钮,单击该按钮会在我的桌面领域中创建三个对象。
func handleButtonClick() {
let a = Pedido()
let b = Lugar()
let c = Carga()
let realm = RealmService.shared.realm
try! realm.write {
realm.add(a)
realm.add(b)
realm.add(c)
}
}
运行此代码并单击按钮,我的桌面上会出现三个文件; DesktopRealm.realm、desktopRealm.realm.lock、desktopRealm.realm.management(这是一个文件夹)。
经检查,desktopRealm.realm 文件包含预期的三个对象。
问题中的领域对象
class Carga: Object{
@Persisted(primaryKey: true) var idCarga : Int32
@Persisted var idPedido : Int32
@Persisted var units : Int32
@Persisted var packages : Int32
@Persisted var kilograms : Double
convenience init(_id: Int32, idPedido: Int32, uds: Int32, pkgs: Int32, kgs: Double) {
self.init()
self.idCarga = _id
self.idPedido = idPedido
self.units = uds
self.packages = pkgs
self.kilograms = kgs
}
}
class Pedido : Object{
@Persisted(primaryKey: true) var idPedido : Int32
@Persisted var idLugar : Int32
@Persisted var cargas = RealmSwift.List<Carga>()
convenience init(_id: Int32, idLugar: Int32, listCargas: RealmSwift.List<Carga>) {
self.init()
self.idPedido = _id
self.idLugar = idLugar
self.cargas = listCargas
}
}
class Lugar : Object{
@Persisted(primaryKey: true) var idLugar : Int32
@Persisted var name : String
@Persisted var pedidos = RealmSwift.List<Pedido>()
convenience init(_id: Int32, name: String, listPedidos: RealmSwift.List<Pedido>) {
self.init()
self.idLugar = _id
self.name = name
self.pedidos = listPedidos
}
}