2015-10-16 2 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

EDIT 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?

EDIT 2:

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

EDIT 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

Большое спасибо !!!

EDIT 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

@ Edman Я редактировал свой qn. PLS посмотреть – perwyl

ответ

0

Почему бы не пожалеть realm использовать конфигурацию по умолчанию? Так как вы установили путь в конфигурации по умолчанию для 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) 

Один аккуратный способ отладки конфигурацию Realm проблемы является использование точек останова или печати журналов до создания экземпляра realm. Выполнение следующего кода позволяет мне узнать, какая настройка по умолчанию будет использоваться.

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.

+0

привет @edman за ответ. Я попробовал 'let realm = try! Realm() ', он падает с той же ошибкой. – perwyl

+0

@perwyl трудно помочь вам намного дальше без доступа к вашему коду. Я скопировал код, который вы предоставили, и он работает в моем проекте. Вывод журнала в моем ответе был сделан с вашим кодом. Возможной причиной для вашей проблемы является некоторое состояние гонки. Возможно, вы пытаетесь создать экземпляр области перед установкой 'defaultConfiguration'. Я обновил ответ с некоторыми советами, которые мне нравятся. Дайте мне знать, если у вас есть дополнительная информация, которая поможет нам решить вашу проблему. – Edman

+0

'' 'Царство.Конфигурация { \t путь = /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); } '' my 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

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)") 
    } 
Смежные вопросы