如何在应用程序开始 运行 代码之前迁移到 运行?
How can I get the migration to run before the app starts to run the code?
我在 swift 应用中使用 realm.io。这是我第一次不得不 运行 迁移,因为我有一个应用程序正在生产中。我更改了其中一个模型并向其添加了几个额外的字段。
我按照文档中的示例进行操作,然后在不起作用时引用了 github 存储库的示例。我认为它可能比文档中的示例更复杂。
这是我的 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()
知道我做错了什么吗?
看起来您 flat-out 将代码从 Realm Swift 'Migration' 示例中复制出来并逐字粘贴。很多代码实际上是 'set-up' 每次示例应用 运行 时进行新的演示迁移,而对于正常的 Realm 迁移实际上不是必需的。
领域迁移有两个组成部分:
增加 Configuration
对象中的模式版本号。 Realm 文件从版本 0 开始,每次要进行新迁移时,将其增加 1。
提供一个迁移块,它将针对您的 Realm 架构版本的每个增量执行多次。虽然块本身是必需的,但它的目的是让您 copy/transform 旧 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()
这按预期工作,在降级时抛出异常(如果使用版本不同的分支)等。还显示了一些示例迁移。
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
等那样编译,但你明白了:)
这最终成为了解决方案。我不能说我自己想出了它,因为我没有。我从 realm 的一位名叫克莱尔的出色工程师那里得到了一些极好的帮助。
以下是需要完成的工作:
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 方法中,而之前它在顶部被调用。
这使得领域可以提前迁移到 运行。正如您可能想象的那样,老实说,我假设在 AppDelegate
中加载 application
函数之后才加载视图。然而,我想我错了。
所以,这将解决它。如果您碰巧 运行 遇到同样的问题,请试一试。
更新:
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
}
我发现这在视图控制器中效果最好:
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()
}()
换句话说,将配置分配移动到块中,以免执行得太晚。
我在 swift 应用中使用 realm.io。这是我第一次不得不 运行 迁移,因为我有一个应用程序正在生产中。我更改了其中一个模型并向其添加了几个额外的字段。
我按照文档中的示例进行操作,然后在不起作用时引用了 github 存储库的示例。我认为它可能比文档中的示例更复杂。
这是我的 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()
知道我做错了什么吗?
看起来您 flat-out 将代码从 Realm Swift 'Migration' 示例中复制出来并逐字粘贴。很多代码实际上是 'set-up' 每次示例应用 运行 时进行新的演示迁移,而对于正常的 Realm 迁移实际上不是必需的。
领域迁移有两个组成部分:
增加
Configuration
对象中的模式版本号。 Realm 文件从版本 0 开始,每次要进行新迁移时,将其增加 1。提供一个迁移块,它将针对您的 Realm 架构版本的每个增量执行多次。虽然块本身是必需的,但它的目的是让您 copy/transform 旧 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()
这按预期工作,在降级时抛出异常(如果使用版本不同的分支)等。还显示了一些示例迁移。
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
等那样编译,但你明白了:)
这最终成为了解决方案。我不能说我自己想出了它,因为我没有。我从 realm 的一位名叫克莱尔的出色工程师那里得到了一些极好的帮助。
以下是需要完成的工作:
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 方法中,而之前它在顶部被调用。
这使得领域可以提前迁移到 运行。正如您可能想象的那样,老实说,我假设在 AppDelegate
中加载 application
函数之后才加载视图。然而,我想我错了。
所以,这将解决它。如果您碰巧 运行 遇到同样的问题,请试一试。
更新:
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
}
我发现这在视图控制器中效果最好:
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()
}()
换句话说,将配置分配移动到块中,以免执行得太晚。