objective-c - Realm 迁移竞争条件

标签 objective-c swift migration realm race-condition

我如何保证在访问 Realm 之前完成 Realm 迁移?迁移 Realm 数据库并开始读/写 Realm 似乎存在竞争条件。这是我的问题:

目前,我在用户启动应用程序时使用迁移关闭来设置 Realm 配置。使用 RLMRealmConfiguration.setDefaultConfiguration(config) 设置 Realm 配置后,我设置 RootViewController 并开始访问 Realm 数据。

但是,当需要迁移时,有时会在迁移完成之前访问 Realm - 导致崩溃(RLMException:对象已被删除或无效)。如果迁移是一个没有回调的异步任务,我们如何保证它在访问 Realm 之前完成?

这是我的 Realm 配置代码:

 class func SetRealmConfigurationForUser(userId: String) {
    let config = RLMRealmConfiguration.defaultConfiguration()

    // migration setup
    config.schemaVersion = 10
    config.migrationBlock = { migration, oldSchemaVersion in
        if oldSchemaVersion < 2 {
            migration.enumerateObjects(ContactUser.className()) { oldObject, newObject in
                // Change primary key from PhoneNumber to Phone_BaseId_Key
                let phone = oldObject?["PhoneNumber"]
                let baseId = oldObject?["BaseId"]

                newObject?["Phone_BaseId_Key"] = String(phone) + "_" + String(baseId)
            }
        }
        if oldSchemaVersion < 3 {
            migration.enumerateObjects(DigitsContact.className()) { oldObject, newObject in
                newObject?["ExternalId"] = ""
            }
        }
        if oldSchemaVersion < 9 {
            migration.deleteDataForClassName(DigitsContact.className())
            migration.deleteDataForClassName(Address.className())
            migration.deleteDataForClassName(Email.className())
            migration.deleteDataForClassName(PhoneNumber.className())
        }
    }

    // Use default directory, but replace filename with the userId
    config.path = (((config.path! as NSString).stringByDeletingLastPathComponent as NSString)
                                            .stringByAppendingPathComponent(userId) as NSString)
                                            .stringByAppendingPathExtension("realm")
    RLMRealmConfiguration.setDefaultConfiguration(config)

最佳答案

根据 Realm's Migrations docs ,迁移仅在打开 Realm 时应用使用设置了架构版本和迁移 block 的配置:

When creating a Realm with this configuration, the migration block will be applied to update the Realm to the given schema version if a migration is needed.

所以如果你调用 SetRealmConfigurationForUser 异步,任何并发的 Realm 访问都将使用以前的默认配置,并且看不到您正在定义的迁移 block 。

执行迁移总是同步发生的,通过在其配置中创建带有迁移 block 的 Realm 隐式地或通过调用 RLMRealm.migrateRealm(_:) 显式地进行。 .

所有其他 Realm 访问(包括读取和写入)都将在迁移完成时被阻止。因此,只要在初始化任何 Realm 之前设置迁移 block 和配置,就不会有竞争条件。

PS:当 oldSchema < 3 时,您在迁移 block 中做了很多无用功。因为你正在设置你所有的 DigitsContact.ExternalId属性为 "" , 然后才删除所有 DigitsContact对象。只需删除 oldSchemaVersion < 3 conditional 及其内容将导致相同的结果。

PPS:您使用 Swift 中的 Realm Objective-C 而不是 Realm Swift 有什么原因吗? Realm 有一个专用的 API,可以更好地在 Swift 中使用:https://realm.io/docs/swift/latest/

关于objective-c - Realm 迁移竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35045045/

相关文章:

ios - 用渐变色 SWIFT 填充未定义的表格

iOS swift UICollectionviewcell 快照错误

ruby-on-rails - 添加具有 Rails 迁移的数据库列并基于另一列填充它

database - 在 VS for Mac (DotNet Core 2) 上使用迁移 CLI 更新数据库

objective-c - NSDate 以正确的方式添加一个月,如果上个月有更多天数则剪裁

objective-c - "Creating selector for nonexistent method ' 的 Xcode 虚假警告比较 :'"

xcode - 将 UI View 添加到 Storyboard

objective-c - iOS 3.0 中 MKMapview 上带有按钮的自定义标注 View

iphone - 按 Objective C 中的子数组值对数组排序

ant - 为 Gradle Javadoc 任务指定所需的包