Realm.io RealmSwift Миграция в другие сферы

Мне нужно сделать миграцию для моего 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:

ошибка: 'попробуй!' В выражении неожиданно возникла ошибка: Ошибка Domain=io.realm Code=0 "Предоставленная версия схемы 0 меньше, чем последняя установленная версия 1." UserInfo=0x170660c00 {NSLocalizedDescription= Предоставленная версия схемы 0 меньше, чем последняя установленная версия 1.}: файл /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 = (ноль); readOnly = 0; schemaVersion = 2; igrationBlock = < NSMallocBlock: 0x170451220>; динамический = 0; customSchema = (ноль); } 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 ответа

Решение

Почему бы не позволить области использовать конфигурацию по умолчанию? Поскольку вы устанавливаете путь в конфигурации по умолчанию getRealmPath(), это должно быть в порядке, чтобы сделать только:

 let realm = try! Realm()

Создавая царство с Realm(path: getRealmPath()) вы переопределяете defaultConfiguration Вы ранее установили. То есть путь царства становится getRealmPath(), но все остальные свойства, которые вы устанавливаете в config теряются, и вместо них используются значения по умолчанию. Это включает schemaVersion = 0 а также migrationBlock = 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.realm, schemaVersion = 2и имеет не ноль migrationBlock,

Вы должны обновить версию схемы до большего значения в конфигурации вашей области всякий раз, когда ваша схема обновляется. То есть в вашем 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.Configuration.schemaVersion а также Realm.Configuration.migrationBlock,

При создании области с этой конфигурацией будет применен блок миграции, чтобы обновить область до указанной версии схемы, если требуется миграция.

Вы правильно установили блок миграции, но не обновили версию схемы. Вот почему блок миграции не выполняется, хотя он предусмотрен в вашей конфигурации.

Разница между версией на диске и версией в вашей конфигурации заключается в том, что вызывает migrationBlock,

Решение 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)")
    }
Другие вопросы по тегам