我有一个跟踪应用程序在后台工作,使用Realm来保持持久性。我注意到有时收到的位置没有保存在Realm中的问题,我认为这可能因为多线程而发生。
这是我的架构:
LocationLogger有一个CLLocationManager实例和我的类的实例,用于持久性:LocationModel。 LocationManager的类型为BaseModel,此实例具有Realm的实例。在BaseModel中,realm从我的类RealmProvider加载一个Realm实例:
lazy var realm: Realm = {
return RealmProvider().loadRealm()
}()!
RealmProvider的代码是这样的:
class RealmProvider {
private var realm: Realm?
private let currentSchemaVersion: UInt64 = 8
func loadRealm() -> Realm? {
if let realm = self.realm {
return realm
}
do {
if let _ = NSClassFromString("XCTest"){
realm = try Realm(configuration: Realm.Configuration(fileURL: nil, inMemoryIdentifier: "test", syncConfiguration: nil, encryptionKey: nil, readOnly: false, schemaVersion: currentSchemaVersion, migrationBlock: nil, deleteRealmIfMigrationNeeded: true, objectTypes: nil))
} else {
realm = try Realm(configuration: Realm.Configuration(encryptionKey: nil, readOnly: false, schemaVersion: currentSchemaVersion, migrationBlock: nil, deleteRealmIfMigrationNeeded: true, objectTypes: nil))
}
}
catch {
logger.error("eror loading Realm!")
}
return realm
}
}
我有一个RealmProvider的原因是在一个地方进行类似版本控制的配置。
你能想象为什么它总是不起作用吗?也许当在线程A中创建LocationLogger时,位置回调会出现在线程B中?其他想法?
每次报告新位置时,创建Realm实例会更好吗?那我怎么做架构配置呢?
对最终解决方案的建议:
class RealmProvider {
static private let currentSchemaVersion: UInt64 = 8
private lazy var configuration: Realm.Configuration = {
if let _ = NSClassFromString("XCTest") {
return Realm.Configuration(inMemoryIdentifier: "test", schemaVersion: currentSchemaVersion, deleteRealmIfMigrationNeeded: true)
}
return Realm.Configuration(schemaVersion: currentSchemaVersion, deleteRealmIfMigrationNeeded: true)
}()
public var realm: Realm {
var tempRealm: Realm?
do {
tempRealm = try Realm(configuration: configuration)
}
catch {
logger.error("eror loading Realm!")
}
if let tempRealm = tempRealm{
return tempRealm
}
return self.realm
}
}
答案 0 :(得分:0)
是。最好是按需创建Realm
实例,而不是提前创建实例并保留它。由于Realm对象是线程限制的,因此在线程A上创建Realm
,然后尝试在线程B上与它进行交互将导致异常。
当调用Realm(configuration:)
时,Realm本身将在内部缓存该对象,并在每次后续调用时返回相同的对象。该对象保留在缓存中,直到创建它的自动释放池耗尽。
就像我上面所说,Realm
对象是线程限制的。在新线程上运行时,必须创建Realm
的新实例。尝试从另一个线程传递Realm
的实例将触发异常。这是为什么建议不要保留Realm
的实例的主要原因,特别是如果存在后台操作。
领域Configuration
对象,只要它们在创建 线程安全后未被修改。因此,创建和保留Configuration
实例,然后重新使用此实例在任何后续线程上创建Realm
实例是完全合理的。
所以要修改上面的例子:
class RealmProvider {
private let currentSchemaVersion: UInt64 = 8
private lazy var configuration: Configuration = {
if let _ = NSClassFromString("XCTest") {
return Realm.Configuration(inMemoryIdentifier: "test", schemaVersion: currentSchemaVersion,deleteRealmIfMigrationNeeded: true)
}
return Realm.Configuration(schemaVersion: currentSchemaVersion, deleteRealmIfMigrationNeeded: true)
}()
public var realm: Realm? {
var realm: Realm?
do {
realm = try Realm(configuration: configuration)
}
catch {
logger.error("eror loading Realm!")
}
return realm
}
}