Crash when using deleteRealmIfMigrationNeeded with Realm in Swift - swift

I'm doing the following inside of didFinishLaunchingWithOptions:
let config = Realm.Configuration(
schemaVersion: 0,
deleteRealmIfMigrationNeeded: true
)
Realm.Configuration.defaultConfiguration = config
let realm = try! Realm()
Basically, while developing, I don't want to worry about migrations and just want to clear the database whenever the schema changes. My understanding is that's exactly what deleteRealmIfMigrationNeeded is for.
The problem is that sometimes it crashes while trying to initialize Realm with the following error:
fatal error: 'try!' expression unexpectedly raised an error: Error Domain=io.realm Code=5 "Directory at path '/Users/rock/Library/Developer/CoreSimulator/Devices/D626848E-14D5-47AC-8FFB-9B67D024DEF1/data/Containers/Data/Application/6F71103C-9E10-4131-BED4-D96445FABA52/Documents/default.realm' does not exist."
The default.realm file is getting removed, presumably because of deleteRealmIfMigrationNeeded, but then isn't getting recreated (as I'd expect) when initializing Realm with that last line.
Interestingly, if I manually delete default.realm.lock and then restart the app, it'll work.
Am I doing this wrong? Could this be a bug? (I'm using Realm Swift 2.4.1)

I just came across the same problem and the solution in my case was to turn off the Realm Browser if you have it open.
Cheers!

I discovered that turning off encryption when setting up the Realm will allow you to have the Realm Browser open at the same time.

Related

Getting error in realm when i try to add new property in realm object

Thread 1: Fatal error: 'try!' expression unexpectedly raised an error:
Error Domain=io.realm Code=1 "Provided schema version 0 is less than
last set version 1." UserInfo={NSLocalizedDescription=Provided schema
version 0 is less than last set version 1., Error Code=1}
Getting this error when I try to add new property in Realm
Not finding any solution for this in swiftui
That's a normal error you will receive during development as you are changing your model and properties around.
The schema version is set to 1 (or it was set to 1) and then you modified an object so you should set schema version to 2 via a migration.
From the docs
Realm Database can automatically migrate added properties, but you
must specify an updated schema version when you make these changes.
If you're just in development, you could also just delete the Realm file and the objects will be built again with schema version 1.
Please see the documentation for Realm Migrations.
We've do that a LOT during the early stages of development so we have a button in our UI that just deletes the Realm files - keeping in mind that upon app start, you cannot touch the realm file for this to work. Once you've touched it, it's 'open' and cannot be deleted through code.
func deleteRealm() {
do {
//return the config pointing to where the realm file is located - we
// keep ours in the project folder initially
let config = gGetConfig()
let isSuccess = try Realm.deleteFiles(for: config)
print("deleted realm: \(isSuccess)")
} catch let err as NSError {
print(err.localizedDescription)
}
}
Edit: Sometimes you can nil the Realm out and then delete it via code but Realm is quite stubborn and sometimes that doesn't work either.

Realm Migration Swift

I added a new Class ,newClass, to my Realm file through Realm Studio to allow users to manage an array of items. I also created swift file to manage the new class in XCode.
Since running the app immediately after doing the above, all my data from the firstClass, has disappeared (not a problem the user adds all data in this class on startup, I can repopulate whilst testing the app.)
My app now crashes whenever it reaches any code let realm = try! Realm(). I have commented out or removed references to these to see if it is a localised problem, but it still continuous to crash with the following similar errors depending on the VC it crashes on when during let realm = try! Realm().
schema version 1
Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=io.realm Code=1 "Provided schema version 0 is less than last set version 1." UserInfo={NSLocalizedDescription=Provided schema version 0 is less than last set version 1., Error Code=1}: file /Users/UserName/Desktop/AppName/AppName/Custom VC's/AddDataToRealmViewController.swift, line 168
2020-06-27 13:23:10.481817+0100 AppName[4498:173994] Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=io.realm Code=1 "Provided schema version 0 is less than last set version 1." UserInfo={NSLocalizedDescription=Provided schema version 0 is less than last set version 1., Error Code=1}: file /Users/UserName/Desktop/AppName/AppName/Custom VC's/AddDataToRealmViewController.swift, line 168
After doing a little bit of reading around, it suggest I need to migrate my realm file to the new schema? Before I attempt this, would this be the correct course of action to take?

Why does a Realm's schema version reset to 0 after a migration?

I'm trying to perform a Realm migration with the following code:
let version = try! schemaVersionAtURL(Realm.Configuration.defaultConfiguration.fileURL!)
let config = Realm.Configuration(
schemaVersion: version + 1,
migrationBlock: { migration, oldSchemaVersion in
if oldSchemaVersion < 1 {
migration.enumerateObjects(ofType: MyObject.className()) { oldObject, newObject in
// Here I transfer existing data to new properties
}
}
})
Realm.Configuration.defaultConfiguration = config
let _ = try! Realm()
The migration seems to work fine, but the next time the app is relaunched, both the current and old schema versions are 0, despite having been set to 1 by the migration that occurred during the first launch.
But the migration is done, so the if condition is true, and the app crashes with a Realm exception caused by trying to perform the migration again.
Can anyone help me understand what I'm missing? If the configuration is setting the schema version to 1 during the migration, why is it 0 the next time the app is relaunched?
The migration seems to work fine, but the next time the app is
relaunched, both the current and old schema versions are 0,
This is caused when you delete the local Realm file and reinstall it, usually occur when you delete and reinstall the application,
Realm handles migrations automatically all it need to know if there was a new version number that would cause the file to rewrite it self with the new rules.
Now for the crashing part, you are using this, an issue with an open stat on github
let version = try! schemaVersionAtURL(Realm.Configuration.defaultConfiguration.fileURL!)
However i agree with this comment.
I guess there's two issues here:
1- It sounds like schemaVersionAtURL() is creating an empty file if given
a URL for a file that doesn't exist, and it obviously shouldn't be
doing that.
2- In Swift schemaVersionAtURL() should be UInt64? and just
return nil if the file doesn't exist rather than throwing
I recommend using plain Int for version rather than getting it from the file,
as it shows in Realm documents, schemaVersion: 1, and increment it manually this will let you always see what version number you are on and when it crashes you know you did something worthy a migration.
Now for the part where you say.
both the current and old schema versions are 0
When you reinstall your application it simply recreate the file with version 0 because the new rules your code implemented to Realm its just simple new file so setting schema version to lower in code would not do pretty much, however this is not recommended because when you go live people will not reinstall the application they will update it, therefore a Realm file is migrated to upper version, however the new users downloading the application with version number 0, so think about it more as a change need to be made rather than an increment number only bigger is better.
Turns out the issue was actually calling Realm before the migration was performed. I'd forgotten a bit of code I had running in willFinishingLaunchingWithOptions that called it.
Lesson Learned: Only the very first call to Realm performs the migration.

Terminating app due to uncaught exception NSInvalidArgumentException, NSDictionaryM setObject:forKeyedSubscript: key cannot be nil

Hello I'm getting this error simply trying a short database write with firebase on iOS using swift. My code is crashing immediately after hitting the Firebase().Database().reference() line. I am running Firebase 4. I have imported Firebase into my AppDelegate and am calling this code inside of func application.
FirebaseApp.configure()
let myDatabase = Firebase.Database().reference()
myDatabase.setValue("We've got data!")
Firebase database treats data as key/value pairs, so when you want to setValue make sure it is currently under a key value. By calling Firebase.Database().reference() you are just accessing the root path of your database, which no key value is pointed. You need to explicitly address the key (e.g. Firebase.Database().reference().child("data").setValue("We've got data!"))
or using childByAutoId().setValue() to let firebase help you generate a key ID.

CKAsset in server record contains no fileURL, cannot even check for nil

I am testing a sync conflict when I save a record that contains a CKAsset (simply a JPG image) using CKModifyRecordsOperation with a save policy of .IfServerRecordUnchanged. I am getting the error CKErrorCode.ServerRecordChanged. This CKError returns me useful information for conflict resolution, including the CKRecord I tried to save, and the current server version of the record. The first is in error.userInfo[CKRecordChangedErrorClientRecordKey] the second is in error.userInfo[CKRecordChangedErrorServerRecordKey].
My problem is I am trying to access the server record's CKAsset with this code:
if let photoAsset = rec["myPhoto"] as? CKAsset {
print("PhotoAsset.fileURL: \(photoAsset.fileURL)") // BAD_ACCESS ERROR HERE
self.myPartner.photo = NSData(contentsOfURL: photoAsset.fileURL)
}
I don't get how this is possible. But after further investigating, I print out the client and server CKRecords and the server one is missing the 'path' property.
client CKAsset...myPhoto (modified) -> CKAsset: 0x7b960d90; path=~/tmp/BF185B2C-7A39-4730-9530-9797E843243Aphoto, size=373959, uploadRank=0, uploadReceipt=A92Eg1qoyPG7yrg3, UUID=3C2D5DC8-4FF5-4A81-853B-395FC1C59862, referenceSignature=<012fd149 200fc600 617e3907 88763e3e 5002abbf 5b>, flags=uploaded, wrappedEncryptionKey=, signature=<0134a297 38d52f5f 9275bfba fce5b1a8 3d6b9692 d3>
server CKAsset...myPhoto = CKAsset: 0x7be700d0; referenceSignature=<015337bd 84409893 7c014f46 36248d27 ce911dc3 7a>, size=373959, uploadRank=0, UUID=DF5D2EB4-033C-49A2-AF52-6055B5A44106, wrappedEncryptionKey=<767e7cfd d1e62110 32119ee9 f6f026b3 5bcf0cc3 8053a4de>, signature=<0134a297 38d52f5f 9275bfba fce5b1a8 3d6b9692 d3>
Notice how path=~/tmp/C706423B-A3E8-4051-A9B3-483C718BFBF5photo is missing from the server one? Can anyone explain this? To fix it I try to avoid touching the CKAsset from the server record. I would like to at least be able to check for nil. I wanted to put this out there in case it helps anyone else.
Due to the crash on accessing fileURL, this is most likely a framework bug. Probably an oversight on account of the CKRecord being buried in a dictionary. I just follow it up with a regular fetch(withRecordID:).
I'm experiencing this issue as well on iOS 11.2.1 when accessing CKAsset from serverRecord property in CKRecord. It's a little bit frustrating. A workaround is fetching the object once again via func fetch(withRecordID... and then access fileURL.
This seems like the correct behavior, not a bug.
CloudKit informed you that your write operation failed because you weren't working from the latest CKRecord and gave you a non-hydrated version of the server's current CKRecord so you could determine which fields were different from your starting point. The rest is up to you.
If CloudKit returned the fully hydrated server record in the error response for a write operation, it would potentially waste enormous amounts of bandwidth/resources.
That is why CKAssets exist: to separate the size-constrained key-value fields associated with a CKRecord from the unlimited-size binary assets that can be attached to them.