Objective c 域迁移竞赛条件

Objective c 域迁移竞赛条件,objective-c,swift,migration,realm,race-condition,Objective C,Swift,Migration,Realm,Race Condition,如何保证域迁移在访问域之前完成?在迁移领域数据库并开始读/写领域时,似乎存在竞争条件。这是我的问题: 目前,当用户启动应用程序时,我正在使用迁移关闭来设置领域配置。使用RLMRealmConfiguration.setDefaultConfiguration(config)设置领域配置后,我将设置RootViewController并开始访问领域数据 但是,当需要迁移时,有时会在迁移完成之前访问领域-导致崩溃(RLMException:Object已被删除或无效)。如果迁移是一个没有回调的异步任

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

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

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

以下是我的领域配置代码:

 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)
class func SetRealmConfigurationForUser(userId:String){
让config=RLMRealmConfiguration.defaultConfiguration()
//迁移设置
config.schemaVersion=10
config.migrationBlock={migration,oldSchemaVersion in
如果oldschemaversation<2{
migration.enumerateObjects(ContactUser.className()){oldObject,newObject在
//将主键从PhoneNumber更改为Phone_BaseId_键
让电话=旧对象?[“电话号码”]
让baseId=oldObject?[“baseId”]
新对象?[“电话\基本ID \基本ID”]=字符串(电话)+“\基本ID”+字符串(基本ID)
}
}
如果Oldschemaversation<3{
enumerateObjects(DigitsContact.className()){oldObject,newObject在
新对象?[“外部ID”]=“”
}
}
如果Oldschemaversation<9{
migration.deleteDataForClassName(DigitsContact.className())
migration.deleteDataForClassName(Address.className())
migration.deleteDataForClassName(Email.className())
migration.deleteDataForClassName(PhoneNumber.className())
}
}
//使用默认目录,但将文件名替换为用户ID
config.path=((config.path!作为NSString.stringByDeletingLastPathComponent作为NSString)
.stringByAppendingPathComponent(userId)作为NSString)
.stringByAppendingPathExtension(“领域”)
RLMRealmConfiguration.setDefaultConfiguration(配置)
根据,迁移仅在使用设置了架构版本和迁移块的配置打开
领域时应用:

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

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

执行迁移总是同步进行的,可以通过在配置中创建带有迁移块的域隐式执行,也可以通过调用显式执行

所有其他领域访问(读写)都将在迁移完成时被阻止。因此,只要在初始化任何领域之前设置了迁移块和配置,就不应该存在争用条件

PS:oldSchema<3
时,您在迁移块中做了大量浪费的工作,因为您将所有的
DigitsContact.ExternalId
属性设置为
“”
,然后只删除所有
DigitsContact
对象。只需删除
oldSchemaVersion<3
条件及其内容,就会得到相同的结果


PPS:您使用Swift中的Realm Objective-C而不是Realm Swift有什么原因吗?Realm有一个专用的API,从Swift中使用会更好:

SetRealmConfiguration ForUser是同步调用的,所以必须是在调用某个领域之前访问了该领域。我现在怀疑这是在单例中发生的,因为Realm可能在SetRealmConfiguration for User之后才能访问。谢谢,这更有意义。另外,我使用的是Obj-C领域,因为该项目是Swift和Obj-C的混合体。我只是想澄清一下:即使在migrationBlock完成之前调用setDefaultConfiguration,领域也会阻止所有访问,直到migrationBlock完成?