我有一个在后台运行的跟踪应用程序,它使用 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 的原因是为了将模式版本控制之类的配置集中在一个地方。
你能想象为什么这并不总是有效吗?也许当 LocationLogger 在线程 A 中创建并且位置回调出现在线程 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
}
}
最佳答案
是的。最好按需创建 Realm 实例,而不是提前抢先创建实例并保留它。由于 Realm 对象是线程限制的,因此在线程 A 上创建 Realm,然后尝试在线程 B 上与其交互将导致异常。
当调用Realm(configuration:)
时,Realm本身将在内部缓存该对象,并在每次后续调用时返回相同的对象。该对象保留在缓存中,直到创建它的自动释放池被耗尽为止。
就像我上面所说的,Realm
对象是线程限制的。在新线程上运行时,有必要创建一个新的Realm
实例。尝试从另一个线程传递Realm
实例将触发异常。这是建议不要保留 Realm
实例的主要原因,尤其是在存在后台操作的情况下。
Realm 配置
对象,只要它们在创建后不被修改都是线程安全的。因此,创建并保留一个 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
}
}
关于swift - 多线程环境中的 Realm,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43775459/