Realm migrations in Swift
You will need to invoke the migration. Merely creating a configuration, won't invoke it. There are two ways of doing this:
Set your configuration with migration as Realm's default configuration-
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
if oldSchemaVersion < 1 {
migration.enumerate(WorkoutSet.className()) { oldObject, newObject in
newObject?["setCount"] = setCount
}
}
}
)
Realm.Configuration.defaultConfiguration = config
OR
- Migrate manually using migrateRealm :
migrateRealm(config)
Now your migration should work properly.
Realm Migration: Migrating objects to another
You don't need to do anything with LinkingObjects
, realm calculates those automatically when you query them.
All you'll need to do in your migration is set media
to be a new Media
object with the values you already have.
Other notes:
- The second
enumerateObjects
isn't needed. - You can remove
image
,coverImage
, andvideo
fromItem
since you're moving those value toMedia
Edit: This is what you would need to have in your migration.
let media = Media()
media.fullImage = oldItem?["image"] as! String
media.thumbnailImage = oldItem?["coverImage"] as! String
media.video = oldItem?["video"] as! String
newItem?["media"] = media
Swift Realm migration create reference from old type to new one
After long testing and trying different possibilities I managed to migrate the data.
Here is what I did to accomplish this.
I used this as a base:
class RealmMigrationObject {
let migration: () -> ()
init(migration: @escaping () -> ()) {
self.migration = migration
}
}
and derived classes from that. Something like:
class MigrationObjectToThree: RealmMigrationObject {
init() {
super.init(migration: MigrationObjectToThree.migration)
}
private static func migration() {
print("Migration to three | migration")
var imageInfos: [ImageInfo] = []
let config = Realm.Configuration(schemaVersion: 3, migrationBlock: { migration, oldSchemaVersion in
print("Migration to three | migrationBlock")
print("RealmMigration: Applying migration from \(oldSchemaVersion) to 3")
migration.deleteData(forType: "ExploreSectionObjectRealm")
migration.enumerateObjects(ofType: "ImageInfoRealm") { oldInfo, newObject in
guard let oldInfo = oldInfo else {
return
}
guard let id = oldInfo["id"] as? String,
let url = oldInfo["url"] as? String,
let url500 = oldInfo["url500"] as? String,
let url400 = oldInfo["url400"] as? String,
let url300 = oldInfo["url300"] as? String,
let url200 = oldInfo["url200"] as? String,
let url100 = oldInfo["url100"] as? String,
let colorString = oldInfo["color"] as? String,
let color = UIColor(hexString: colorString) else {
return
}
imageInfos.append(ImageInfo(id: id,
url: url,
url500: url500,
url400: url400,
url300: url300,
url200: url200,
url100: url100,
color: color))
}
})
Realm.Configuration.defaultConfiguration = config
do {
let realm = try Realm(configuration: config)
print("Realm is located at: \(realm.configuration.fileURL?.description ?? "")")
print(realm.configuration.fileURL?.description ?? "") // Printing here on purpose as it's easier to copy
} catch {
print("Realm Error: \(error), trying to rebuild realm from scratch")
let deleteMigrationConfig = Realm.Configuration(schemaVersion: RealmHelper.schemaVersion,
deleteRealmIfMigrationNeeded: true)
do {
_ = try Realm(configuration: deleteMigrationConfig)
} catch {
print("Failed to instantiate: \(error.localizedDescription)")
}
}
RealmHelper.removeRealmFiles()
Realm.Configuration.defaultConfiguration = Realm.Configuration(schemaVersion: 3)
imageInfos.forEach({ $0.save() })
}
}
From that I just created all migration for the difference between the current schema version and target schema version on looped over all migrations simply executing the migration
function of that given object.
Understanding migrations in Realm - Swift
No, in this case you don't need to perform a migration. You only need to perform a migration in case existing objects need to be changed (adding/removing properties of existing Realm model classes).
If you add a new class to Realm, you don't need to perform a migration.
In most cases, Realm can automatically perform the migration and all you need to do is increase your schema version by 1. However, if you are for example combining two existing properties into a new one, you need to handle that manually in your migration block.
Realm migration introducing primary key
Did you just try to increment schema version and add property deleteRealmIfMigrationNeeded
to true ?
Realm.Configuration.defaultConfiguration = Realm.Configuration(
schemaVersion: 2,
migrationBlock: { migration, oldSchemaVersion in },
deleteRealmIfMigrationNeeded: true
)
EDIT:
Sorry, it's not true because you need to keep only oldest people so try use delete
method of realm migration object:
let config = Realm.Configuration(
schemaVersion: 1,
migrationBlock: { migration, oldSchemaVersion in
switch oldSchemaVersion {
case 0:
var objects: [String: Any] = []
migration.enumerateObjects(ofType: MyData.className()) {
(oldObject, newObject) in
if let age = oldObject["age"] as? Int, age > objects[oldObject["name"]] {
migration.delete(oldObject["name"])
objects[oldObject["name"]] = oldObject
} else {
migration.delete(oldObject)
}
}
default:
break
}
})
https://realm.io/docs/swift/latest/api/Classes/Migration.html#/s:FC10RealmSwift9Migration6deleteFCS_13DynamicObjectT_
Unable to do a Realm migration in Swift
This exception will be thrown when stored data doesn’t match the model you have in code.
You shouldn’t need to do anything in the migration block, however you will need to trigger a migration by updating the value of Realm.Configuration.schemaVersion
, e.g.:
schemaVersion: 3,
How can I avoid migration in RealmSwift
There are two ways to skip migration error regardless schema changes.
Use
deleteRealmIfMigrationNeeded
property. If it istrue
, recreate the Realm file with the provided schema if a migration is required.let config = Realm.Configuration(deleteRealmIfMigrationNeeded: true)
Realm.Configuration.defaultConfiguration = config
let realm = try! Realm()
...Increment schema version every launch. Realm has auto migration feature. If you don't need to migrate existing data, you can just increment schema version. Schema will be changed by Realm automatically.
let config = Realm.Configuration(schemaVersion: try! schemaVersionAtURL(Realm.Configuration.defaultConfiguration.fileURL!) + 1)
Realm.Configuration.defaultConfiguration = config
let realm = try! Realm()
...
Access list property in Realm migration
I don't know what the full scope is of what your trying to do but a specific answer to the question would be:
let test = [ old!["bar"] ]
EDIT
The OP added some additional information. The goal is to be able to access the values within the bar List property. Here's some quickie code that iterates over that list and outputs the index and the object (as a string) to the console.
migration.enumerateObjects(ofType: Foo.className()) { oldItem, newItem in
let dynamicBarList = oldItem?.dynamicList("stringList")
if let list = dynamicBarList {
let myArray = list._rlmArray
let lastIndex = myArray.count - 1
for index in 0...lastIndex {
let object = myArray.object(at: index)
let value = "\(object)" //make the NSTaggedPointerString a String
print(index, value)
}
}
}
Realm migration causing intermittent crashes for some users
I may be mis-reading the question so please add a comment if I miss the mark and I will update the answer.
It appears you have a Realm object with no defined primary key
class Stuff2: Object {
@objc dynamic var primaryKeyTag = ""
@objc dynamic var localID = ""
}
and then at some point a primary key was needed and you want to make the localID property that primary key, so you added the primaryKey function to the object (that will trigger a migration)
class Stuff2: Object {
@objc dynamic var primaryKeyTag = ""
@objc dynamic var localID = ""
override static func primaryKey() -> String? {
return "localID"
}
}
So the only thing needed in that case is to take the old localID value and assign it to the new localID property (which is now the primary key)
let vers = UInt64(1)
let config = Realm.Configuration( schemaVersion: vers, migrationBlock: { migration, oldSchemaVersion in
if (oldSchemaVersion < vers) {
migration.enumerateObjects(ofType: TestClass.className()) { oldItem, newItem in
let oldVar = oldItem!["localID"] as! String
newItem!["localID"] = oldVar
}
}
})
There are two getcha's; primary keys cannot be nil and must be unique so there should be some error checking to ensure that's enforced.
Well, technically one objects primary key could be nil, but again, to enforce uniqueness it would be the only one.
Related Topics
Using Apple's New Audioengine to Change Pitch of Audioplayer Sound
Conflicting Definition of Swift Struct and Array
Scenekit -- How to Get Animations for a .Dae Model
How to Implement Interstitial Iads in Swift(Xcode 6.1)
Swift .Uppercasestring or .Lowercasestring Property Replacement
Class Level or Struct Level Method in Swift Like Static Method in Java
Why Is My Swift Loop Failing with Error "Can't Form Range with End < Start"
Swiftui Views with a Custom Init
Enable + Disable Auto-Layout Constraints
Should Iboutlet Be Weak or Strong Var
Using Environmentobject in Watchos
Function Taking a Variable Number of Arguments
Swift - Lazy Var VS. Let When Creating Views Programmatically (Saving Memory)
What Language Is Swift Written In
Forcing Nspersistentcontainer Change Core Data