2015-10-16 88 views
0

我需要为我的Other Realm进行迁移。Realm.io RealmSwift其他领域迁移

我通过这种方法得到了我的领域路径(AppDelegate)。如果用户登录之前,我将检索用户的领域,否则我只会使用Default Realm

func getRealmPath() -> String { 
    let preferences : NSUserDefaults = NSUserDefaults() 
    let username = preferences.objectForKey(usernameKey) as! String? 

    if username != nil { 
     let realmName = ("\(username!).realm") 

     print("RealmName: \(realmName)", terminator: "") 

     let documents = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString 
     return documents.stringByAppendingPathComponent(realmName) 
    }else{ 
     return Realm.Configuration.defaultConfiguration.path! 
    } 
} 

我通过这种方法进行了迁移(在AppDelegate:didFinishLaunchingWithOptions之内调用)。

func updateRealm(){ 

    let config = Realm.Configuration(path: getRealmPath(), schemaVersion: 2, migrationBlock: { (migration, oldSchemaVersion) -> Void in 

     print("oldSchemaVersion \(oldSchemaVersion)") 

     migration.create("RLMStringTimestamp", value: ["pKey": NSUUID().UUIDString, "value": "", "updatedAt": NSDate(), "createdAt": NSDate(), "deletedAt": Date().getInitDate(), "updatedBy" : " ", "syncedAt": NSDate() ])   

     if oldSchemaVersion < 2 { 

      //MIGRATION 
      let firstNameTimeStamp = RLMStringTimestamp(newValue: oldObject!["firstName"] as? String) 
      migration.create("RLMStringTimestamp", value: firstNameTimeStamp) 
      newObject!["firstName"] = firstNameTimeStamp 

     } 
     } 

     Realm.Configuration.defaultConfiguration = config 

     //EDIT 2 
     Realm.Configuration.defaultConfiguration.path = getRealmPath() 

    //EDIT 1 
    //<strike>let realm = try! Realm(path: getRealmPath())</strike> 

    //EDIT 4 
    print(Realm.Configuration.defaultConfiguration) 

    //EDIT 3 
    let realm = try! Realm() 
    } 

For my RLMCustomer Object, i modified var firstName: String = "" to var firstName: RLMStringTimeStamp!

即使我改变 schemaVersion的东西非常高, migrationBlock没有得到调用。任何人都可以帮助我发现我失踪或做错了什么?

运行的应用程序后,它与bad excess, code = 257

编辑崩溃1:

error: 'try!' expression unexpectedly raised an error: Error Domain=io.realm Code=0 "Provided schema version 0 is less than last set version 1." UserInfo=0x170660c00 {NSLocalizedDescription=Provided schema version 0 is less than last set version 1.}: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-700.0.59/src/swift/stdlib/public/core/ErrorType.swift, line 50

这似乎是读错的配置文件,我怀疑的错误是由于 Realm.Configuration.defaultConfiguration = config我该怎么办设置配置为 Other Realm

编辑2:

I make my default realm to contains the name and path of my other realm

编辑4:

看来这个配置文件是否正确。如果没有来自旧领域的客户记录,我可以毫无问题地运行应用程序。只有在老领域有客户记录时才会崩溃。我可以从oldObject["firstName"]

print(Realm.Configuration.defaultConfiguration)

Realm.Configuration { path = /var/mobile/Containers/Data/Application/8670C084-75E7-4955-89FB-137620C9B00D/Documents/perwyl.realm; inMemoryIdentifier = (null); encryptionKey = (null); readOnly = 0; schemaVersion = 2; migrationBlock = <NSMallocBlock: 0x170451220>; dynamic = 0; customSchema = (null); } oldSchemaVersion 0

,不胜感谢得到的值!

编辑5:解决我的问题

I'm not sure why it crashes if i assign StringTimestamp object directly to newObject.

let firstName = (oldObject!["firstName"] as? String)! 
let firstNameTimeStamp = StringTimestamp(newValue: firstName) 
let testName = migration.create("StringTimestamp",value:  firstNameTimeStamp) 
newObject!["firstName"] = firstNameTimeStamp //Crashes 
newObject!["firstName"] = testName //works 

感谢大家的准则! :)

+1

文件打开时,迁移被称为,这只要您检索默认领域发生在你的情况下使用。你能不能展示代码呢? – marius

+0

当您尝试实例化_realm_时会出现什么错误? – Edman

+0

@埃德曼我编辑了我的qn。请看看 – perwyl

回答

0

为什么不让境界使用默认配置?既然你设置为getRealmPath()在默认配置的路径,它应该是确定只是做:

let realm = try! Realm() 

通过与Realm(path: getRealmPath())实例化境界要覆盖defaultConfiguration您之前设置。也就是说,领域的路径变为getRealmPath(),但在config中设置的所有其他属性都会丢失,并使用默认值。这包括schemaVersion = 0migrationBlock = nil

初始化程序如Realm(path:)Realm(configuration:)的意图是允许您使用非默认配置的其他配置。如果你想要的是使用默认配置的修改版本,那么你就需要做的东西线:

// Get a copy of the default configuration 
var otherConfig = Realm.Configuration.defaultConfiguration 
// Update the copy with what you need 
otherConfig.path = "/some/path/otherRealm.realm" 
// Use the updated configuration to instantiate a realm 
let otherRealm = try! Realm(configuration: otherConfig) 

一个巧妙的方法来调试领域配置问题是通过设置断点或印刷在实例化领域之前的日志。运行以下代码可以让我知道什么是要使用的默认配置。

print(Realm.Configuration.defaultConfiguration)) 
let realm = try! Realm() 

输出看起来像

Realm.Configuration { 
    path = /Users/<full-path-omitted>/edman.realm; 
    schemaVersion = 2; 
    migrationBlock = <__NSMallocBlock__: 0x7faee04ac590>; 
    // other properties... 
} 

通过观察它,我敢肯定,我境界是与edman.realmschemaVersion = 2路径实例化,它具有非空migrationBlock

+0

hi @edman感谢您的回复。我试过'让realm =试试! Realm()',它崩溃时有相同的错误。 – perwyl

+0

@perwyl无法访问您的代码很难再帮助您。我复制了你提供的代码,它在我的项目中工作。我的答案中的日志输出是用你的代码完成的。你的问题的一个可能的原因是一些竞争条件。您可能在设置'defaultConfiguration'之前尝试实例化领域。我已经用我喜欢使用的一些提示更新了答案。让我知道你是否有更多的信息可以帮助我们解决你的问题。 – Edman

+0

'''境界。配置{ \t path = /var/mobile/Containers/Data/Application/D6CD93A5-AEBF-45FC-B7BD-46DCBC21066F/Documents/perwyl.realm; \t inMemoryIdentifier =(null); \t encryptionKey =(null); \t readOnly = 0; \t schemaVersion = 2; \t migrationBlock = <__ NSMallocBlock__:0x170447320>; \t dynamic = 0; \t customSchema =(null); }'''我的oldSchemaVersion是0.如果旧领域是空的,没有错误会抛出,只有当我有一个旧的客户记录时它才会崩溃。 'RLMStringTimestamp'是schemaVersion 2中新创建的一个对象。 – perwyl

0

无论何时更新模式,您都必须将架构版本更新为领域配置中的较大值。也就是说,在你的updateRealm()功能

let config = Realm.Configuration(
    path: getRealmPath(), 
    schemaVersion: 3, // any value larger than previous version 
    migrationBlock: { /* ... */} 
}) 

Realm.Configuration.defaultConfiguration = config 
let realm = try! Realm() 

realm docs

You define a migration and the associated schema version by setting Realm.Configuration.schemaVersion and Realm.Configuration.migrationBlock .

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.

您正确设置了迁移块,但不更新模式版本。这就是为什么迁移块没有被执行,虽然它是在你的配置中提供的。

磁盘版本和配置版本之间的区别是触发migrationBlock

+0

嗨@Edman,我更新了我的模式版本,只有当我将StringTimestamp赋值给'newObject'时,其他迁移才能正常工作(Int,String等)。是否因为StringTimestamp对象在旧版本中不存在? – perwyl

+0

@perwyl我无法重现你的问题修改你的[github项目](https://github.com/perwyl/RealmMigrationTest)。这两者都使用'firstNameTimeStamp'或'testName'。我也不确定你是否仍然有问题。如果是这样,你可以用当前的问题更新github项目吗?如果您的问题得到解决,请考虑接受或提高我的答案。 – Edman

0

雨燕3.0解决方案

class func realmConfigs(_ realmName: String) -> RealmSwift.Realm.Configuration?{ 
    var config = Realm.Configuration() 
    config.readOnly = true 
    // Use the default directory, but replace the filename with the username 
    let fileURLString = Bundle.main.path(forResource: realmName, ofType: "realm") 
    guard fileURLString != nil else { 
     return nil 
    } 
    config.fileURL = URL(string: fileURLString!) 
    config.schemaVersion = UInt64(1.0) 
    // Set this as the configuration used for the default Realm 

    return config 
} 

,并会这样

var realm : Realm? 
    do{ 

     let config = realmConfigs("FILE_NAME") 
     Realm.Configuration.defaultConfiguration = config! 
     realm = try Realm(fileURL: realmURL) 
    } 
    catch { 
     print("Opening realm file error: \(error)") 
    }