7

我在 swift 应用程序中使用 realm.io。自从我有一个生产应用程序以来,这是我第一次不得不运行迁移。我更改了其中一个模型并添加了几个额外的字段。

我按照文档中的示例进行操作,然后在不起作用时引用了 github repo 的示例。我认为它可能比文档中的示例更复杂。

这是我的 appdelegate.swift 文件中的内容:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        print ("i'm in here")
        // Override point for customization after application launch.

        // Inside your application(application:didFinishLaunchingWithOptions:)

        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        window?.rootViewController = UIViewController()
        window?.makeKeyAndVisible()

        // copy over old data files for migration
        let defaultPath = Realm.Configuration.defaultConfiguration.path!
        let defaultParentPath = (defaultPath as NSString).stringByDeletingLastPathComponent

        if let v0Path = bundlePath("default-v0.realm") {
            do {
                try NSFileManager.defaultManager().removeItemAtPath(defaultPath)
                try NSFileManager.defaultManager().copyItemAtPath(v0Path, toPath: defaultPath)
            } catch {}
        }

        let config = Realm.Configuration(
            // Set the new schema version. This must be greater than the previously used
            // version (if you've never set a schema version before, the version is 0).
            schemaVersion: 1,

            // Set the block which will be called automatically when opening a Realm with
            // a schema version lower than the one set above
            migrationBlock: { migration, oldSchemaVersion in
                // We haven’t migrated anything yet, so oldSchemaVersion == 0
                if (oldSchemaVersion < 1) {
                    // Nothing to do!
                    // Realm will automatically detect new properties and removed properties
                    // And will update the schema on disk automatically
                }
        })

        // define a migration block
        // you can define this inline, but we will reuse this to migrate realm files from multiple versions
        // to the most current version of our data model
        let migrationBlock: MigrationBlock = { migration, oldSchemaVersion in
            if oldSchemaVersion < 1 {

            }

            print("Migration complete.")
        }

        Realm.Configuration.defaultConfiguration = Realm.Configuration(schemaVersion: 1, migrationBlock: migrationBlock)

        // Tell Realm to use this new configuration object for the default Realm
        Realm.Configuration.defaultConfiguration = config

        // Now that we've told Realm how to handle the schema change, opening the file
        // will automatically perform the migration
        _ = try! Realm()


        return true
    }

我觉得奇怪的print从不运行。我在搞砸什么吗?我假设我必须是。

这是文档所说的,我不确定他们是否遗漏了一些东西:

// Inside your application(application:didFinishLaunchingWithOptions:)

let config = Realm.Configuration(
  // Set the new schema version. This must be greater than the previously used
  // version (if you've never set a schema version before, the version is 0).
  schemaVersion: 1,

  // Set the block which will be called automatically when opening a Realm with
  // a schema version lower than the one set above
  migrationBlock: { migration, oldSchemaVersion in
    // We haven’t migrated anything yet, so oldSchemaVersion == 0
    if (oldSchemaVersion < 1) {
      // Nothing to do!
      // Realm will automatically detect new properties and removed properties
      // And will update the schema on disk automatically
    }
  })

// Tell Realm to use this new configuration object for the default Realm
Realm.Configuration.defaultConfiguration = config

// Now that we've told Realm how to handle the schema change, opening the file
// will automatically perform the migration
let realm = try! Realm()

任何想法我做错了什么?

4

4 回答 4

6

这最终成为了解决方案。我不能说我自己想出了它,因为我没有。我从领域一位名叫 Claire 的出色工程师那里得到了一些极好的帮助。

以下是需要做的事情:

class RoomsViewController: UIViewController, UITableViewDelegate {

    var activeRoom = -1
    var room: Room? = nil
    var array = [Room]()

    lazy var realm:Realm = {
        return try! Realm()
    }()


    var notificationToken: NotificationToken?

    @IBOutlet weak var roomsTable: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        array = Array(realm.objects(Room.self))

        setupUI()
        // Set realm notification block
        notificationToken = realm.addNotificationBlock { [unowned self] note, realm in
            // TODO: you are going to need to update array
            self.roomsTable.reloadData()
        }
    }

这是第一个加载的视图控制器,它立即查询领域数据库以构建数组。根据 Claire 的建议,Realm 被延迟加载(或尝试过),构建数组的代码被移到 viewDidLoad 方法中,而之前它在顶部被调用。

这允许领域迁移提前运行。正如您可能想象的那样,我老实说,直到applicationAppDelegate. 然而,我想我错了。

所以,这将解决它。如果您碰巧遇到同样的问题,请试一试。

更新:

下面是 appDelegate 函数现在的样子:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        // Inside your application(application:didFinishLaunchingWithOptions:)

        let config = Realm.Configuration(
            // Set the new schema version. This must be greater than the previously used
            // version (if you've never set a schema version before, the version is 0).
            schemaVersion: 1,

            // Set the block which will be called automatically when opening a Realm with
            // a schema version lower than the one set above
            migrationBlock: { migration, oldSchemaVersion in
                // We haven’t migrated anything yet, so oldSchemaVersion == 0
                if (oldSchemaVersion < 1) {
                    migration.enumerate(Inventory.className()) { oldObject, newObject in
                        // No-op.
                        // dynamic properties are defaulting the new column to true
                        // but the migration block is still needed
                    }
                    migration.enumerate(Profile.className()) { oldObject, newObject in
                        // No-op.
                        // dynamic properties are defaulting the new column to true
                        // but the migration block is still needed
                    }
                    migration.enumerate(Room.className()) { oldObject, newObject in
                        // No-op.
                        // dynamic properties are defaulting the new column to true
                        // but the migration block is still needed
                    }
                    migration.enumerate(Box.className()) { oldObject, newObject in
                        // No-op.
                        // dynamic properties are defaulting the new column to true
                        // but the migration block is still needed
                    }
                }
        })

        // Tell Realm to use this new configuration object for the default Realm
        Realm.Configuration.defaultConfiguration = config

        // Now that we've told Realm how to handle the schema change, opening the file
        // will automatically perform the migration
        do {
            _ = try Realm()
        } catch let _ as NSError {
            // print error
        }


        return true
    }
于 2016-01-15T05:01:19.603 回答
2

这按预期工作,在降级时抛出异常(如果使用版本不同的分支)等。还显示了一些示例迁移。

    Realm.Configuration.defaultConfiguration = Realm.Configuration(
        // Update this number for each change to the schema.
        schemaVersion: 4,
        migrationBlock: { migration, oldSchemaVersion in
            if oldSchemaVersion < 2 {
                migration.enumerate(SomeObject.className()) { oldObject, newObject in
                    newObject!["newColumn"] = Enum.Unknown.rawValue
                }
            }
            if oldSchemaVersion < 3 {
                migration.enumerate(SomeOtherObject.className()) { oldObject, newObject in
                    newObject!["defaultCreationDate"] = NSDate(timeIntervalSince1970: 0)
                }
            }
            if oldSchemaVersion < 4 {
                migration.enumerate(SomeObject.className()) { oldObject, newObject in
                    // No-op.
                    // dynamic properties are defaulting the new column to true
                    // but the migration block is still needed
                }
            }
    })

显然这不会像SomeObject等一样编译,但你明白了:)

于 2016-01-14T17:56:07.460 回答
1

看起来您完全从 Realm Swift 'Migration' 示例中复制了代码并逐字粘贴。很多代码实际上是在每次运行示例应用程序时“设置”一个新的演示迁移,而对于正常的 Realm 迁移实际上并不是必需的。

Realm 迁移有两个组件:

  1. 碰撞对象中的架构版本号Configuration。Realm 文件从版本 0 开始,每次您想要进行新的迁移时,将其增加 1。

  2. 提供一个迁移块,该块将为您的 Realm 模式版本的每个增量执行多次。虽然块本身是必要的,但它的目的是让您复制/转换旧 Realm 文件中的任何数据。如果您只是添加新字段,则可以将该块留空。

如果您UIViewController在其实现中完全使用 Realm,最好将迁移代码放在代码之前,UIWindow以确保在开始使用它之前已经发生迁移UIViewController(否则您会遇到异常)。

由于您所做的只是向其中添加一些字段,因此这就是您需要的所有代码:

let migrationBlock: MigrationBlock = { migration, oldSchemaVersion in
    //Leave the block empty
}
Realm.Configuration.defaultConfiguration = Realm.Configuration(schemaVersion: 1, migrationBlock: migrationBlock)

window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.rootViewController = UIViewController()
window?.makeKeyAndVisible()
于 2016-01-14T05:22:18.177 回答
1

我发现这在视图控制器中效果最好:

let migrationBlock: MigrationBlock = { migration, oldSchemaVersion in
    //Leave the block empty
}

lazy var realm:Realm = {
    Realm.Configuration.defaultConfiguration = Realm.Configuration(schemaVersion: 1, migrationBlock: migrationBlock)
    return try! Realm()
}()

换句话说,将配置分配移动到块中,这样它就不会执行得太晚。

于 2018-10-04T04:20:10.790 回答