Realm.io RealmSwift其他领域迁移

时间:2015-10-16 09:40:14

标签: xcode swift2 realm realm-migration

我需要为Other Realm进行迁移。

我通过此方法(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()
     }
  

对于我的RLMCustomer对象,我将var firstName: String = ""修改为var firstName: RLMStringTimeStamp!

即使我将schemaVersion更改为非常高的值,migrationBlock也无法接听电话。谁能帮助我发现我错过了什么或做错了什么?

运行应用后,它会与bad excess, code = 257

崩溃

编辑1:

  

错误:&#39;尝试!&#39;表达式意外地引发了错误:错误Domain = io.realm Code = 0&#34;提供的架构版本0小于上次设置的版本1。&#34; UserInfo = 0x170660c00 {NSLocalizedDescription =提供的架构版本0小于上次设置的版本1.}:file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-700.0.59/src/swift/stdlib/public/ core / ErrorType.swift,第50行

它似乎正在读取错误的配置文件,我怀疑错误是由于Realm.Configuration.defaultConfiguration = config如何设置Other Realm的配置?

编辑2:

  

我让我的default realm包含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 =&lt; NSMallocBlock :0x170451220&gt ;;       dynamic = 0;       customSchema =(null);   }   oldSchemaVersion 0

非常感谢!

编辑5:解决我的问题

  

如果我直接将StringTimestamp object分配给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 

感谢大家的指导! :)

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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

  

您可以通过设置来定义迁移和关联的架构版本   Realm.Configuration.schemaVersion和   Realm.Configuration.migrationBlock

     

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

您正确设置了迁移块,但未更新架构版本。这就是迁移块未被执行的原因,尽管它在您的配置中提供。

磁盘版本与配置版本之间的差异是触发migrationBlock的原因。

答案 2 :(得分:0)

Swift 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)")
    }