我如何保证在访问 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/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano
我正在尝试为我的iOS应用程序设置cocoapods但是当我执行命令时:sudogemupdate--system我收到错误消息:当前已安装最新版本。中止。当我进入cocoapods的下一步时:sudogeminstallcocoapods我在MacOS10.8.5上遇到错误:ERROR:Errorinstallingcocoapods:cocoapods-trunkrequiresRubyversion>=2.0.0.我在MacOS10.9.4上尝试了同样的操作,但出现错误:ERROR:Couldnotfindavalidgem'cocoapods'(>=0),hereiswhy:U
我的Gallery模型中有以下查询:media_items.includes(:photo,:video).rank(:position_in_gallery)我的图库模型有_许多媒体项,每个都有一个照片或视频关联。到目前为止,一切正常。它返回所有media_items包括它们的photo或video关联,由media_item的position_in_gallery属性排序。但是我现在需要将此查询返回的照片限制为仅具有is_processing属性的照片,即nil。是否可以进行相同的查询,但条件是返回的照片等同于:.where(photo:'photo.is_processingIS