境界迁移竞争条件

时间:2016-01-27 18:17:17

标签: objective-c swift migration realm race-condition

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

目前,当用户启动应用程序时,我正在使用迁移关闭设置领域配置。一旦使用RLMRealmConfiguration.setDefaultConfiguration(config)设置了领域配置,我就设置了RootViewController并开始访问领域数据。

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

这是我的领域配置代码:

 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)

1 个答案:

答案 0 :(得分:1)

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

  

使用此配置创建Realm时,如果需要迁移,将应用迁移块将Realm更新为给定的架构版本。

因此,如果您异步调用SetRealmConfigurationForUser ,任何并发Realm访问都将使用以前的默认配置,而不会看到您在此过程中的迁移块定义。

执行迁移始终是同步发生的,可以通过在其配置中创建具有迁移块的Realm或通过调用RLMRealm.migrateRealm(_:)显式地隐式实现。

迁移完成时将阻止所有其他Realm访问(读取和写入)。所以只要迁移块和&amp;在任何Realm初始化之前设置配置,应该没有竞争条件。

PS:oldSchema < 3您在迁移阻止中浪费了大量工作,因为您将所有DigitsContact.ExternalId属性设置为"",只是为了DigitsContact然后删除所有oldSchemaVersion < 3个对象。只需删除sig条件及其内容就会产生相同的结果。

PPS:你是否有理由使用Swift的Realm Objective-C而不是Realm Swift? Realm有一个专用的API,可以在Swift中使用得更好:https://realm.io/docs/swift/latest/