I'm trying to remove a property in one of my Realm objects however I'm not sure how to write a migration for this.
I just removed the property from my object's header file but that didn't work as I get this error:
Terminating app due to uncaught exception 'RLMException', reason:
'Migration is required for object type 'Stock' due to the following
errors:
- Property 'percentageOn' is missing from latest object model.'
I know how to write a migration add fields, but how do I remove one?
What David said is correct. If you make sure to perform a migration properly, then Realm can easily handle properties that have been removed as well as added. Unless you actually still need the value in percentageOn, you can even leave the migration block empty like in the example on the Realm website:
// Inside your [AppDelegate didFinishLaunchingWithOptions:]
// Notice setSchemaVersion is set to 1, this is always set manually. It must be
// higher than the previous version (oldSchemaVersion) or an RLMException is thrown
[RLMRealm setSchemaVersion:1
forRealmAtPath:[RLMRealm defaultRealmPath]
withMigrationBlock:^(RLMMigration *migration, NSUInteger oldSchemaVersion) {
// 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
}
}];
// now that we have called `setSchemaVersion:withMigrationBlock:`, opening an outdated
// Realm will automatically perform the migration and opening the Realm will succeed
[RLMRealm defaultRealm];
Related
Whenever I try to check equality between a property on a Realm object and a NSInteger, it throws the following exception:
*** Terminating app due to uncaught exception 'RLMException', reason: 'Attempting to modify object outside of a write transaction - call beginWriteTransaction on an RLMRealm instance first.'
However I am not modifying the object, just accessing it. Do I have to start a write transaction to check equality?
If I put a breakpoint right at the start of the if statement, the next step in throws the exception.
//message is a RLMObject stored in a RLMResults array
if (message.status == 3 || message.status == 4) {
NSLog(#"Message status: %ld", (long)message.status);
}
The issue was that I was querying and modifying the RLMObject elsewhere in the setup of another view controller. This was causing the exception to be thrown. My fault for not looking closely at what my other code was doing.
I am Getting crash in app upgrade scenario. It gives below error and warning. But this issue happens only when I have AppStore build installed and on top of that I install my new testflight build.
If I install developer build on AppStore build, than it works fine.
Error:
[__NSArrayM UTF8String]: unrecognized selector sent to instance
Warning: An RLMRealm instance was deallocated during a write transaction and all pending changes have been rolled back. Make sure to retain a reference to the RLMRealm for the duration of the write transaction.
It crashes straight away when you tap app icon, So, I dont have any stack trace.
Realm version: 0.96.3 &
Xcode version: 7.3
Below is my migration code for that.
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.schemaVersion = 3;
if (oldSchemaVersion < 2)
{
[migration enumerateObjects:DB_Class1.className
block:^(RLMObject *oldObject, RLMObject *newObject) {
newObject[#"thisIsArray_1"] = nil;
}];
[migration enumerateObjects:DB_Class2.className
block:^(RLMObject *oldObject, RLMObject *newObject) {
newObject[#"thisIsInt_1"] = 0;
newObject[#"thisIsInt_2"] = 0;
newObject[#"thisIsInt_3"] = 0;
}];
}
All of the above newObjects are added in this version only.
Update 1: I can see deleteRealmIfMigrationNeededfor android. Is there any eqvivalent in iOS? I only found deleteAllObjects. If so, thn I can simply delete my old realm data and save new one.
Thanks.
Realm Cocoa added the deleteRealmIfMigrationNeeded option (on RLMRealmConfiguration) in version 0.102.0. This should allow you to sidestep your migration issues. See the change notes here.
I'm getting a crash on my App Store update, the migration is handled and even when I see the code Block is being executed I get the Following migration error
'RLMException', reason: 'Migration is required for object type
'LLCachedObject' due to the following errors:
- Property 'resultType' has been added to latest object model.'
This is how I'm handling the Migration
[migration enumerateObjects:LLCachedObject.className
block:^(RLMObject *oldObject, RLMObject *newObject) {
if (oldSchemaVersion < 5) {
newObject[#"resultType"] = kLLResultTypeBrief;
}
}];
and I double-checked that the oldSchemaVersion was 4, and newObject[#"resultType"] is being set properly, this is happening on iOS 9, I'm completely clueless as I've run out of things to checked to find out what is causing this.
So the problem turned out being that we have another project we use for the same app that also has a Realm, we weren't aware that the migration needed to be handled in both sides, so what we are doing now is using the class subsets to specify the Model Clases that every project uses.
For more details https://realm.io/docs/objc/latest/#class-subsets
My iOS app uses core data via multiple threads. I am getting some crash reports with the following message: "'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0x1e07a9b0 ''
I understand what is causing this problem - that the object was deleted but another thread is trying to access it. I am working to solve the problem but I want to add a check in the background thread to see if the object will fault in this manner.
My code at the moment relates to myObject.myValue. Is it possible to do some check, such as:
if (!myObject.myValue) {
return;
}
... so that it will get out of the method before doing anything that could cause such a crash? Or will simply calling myObject.myValue, even to see if it's null, cause such an exception to be thrown?
You could try and use existingObjectWithID:error::
Returns the object for the specified ID.
- (NSManagedObject *)existingObjectWithID:(NSManagedObjectID *)objectID error:(NSError **)error
Discussion
If there is a managed object with the given ID already registered in the context, that object is returned directly; otherwise the corresponding object is faulted into the context.
This method might perform I/O if the data is uncached.
Unlike objectWithID:, this method never returns a fault.
You could dO:
if ([myMOC existingObjectWithID:myObject.objectID error:&error])
...
You should verify that the object exists before accessing it's variables if you're having issues where the object may be deleted on another thread.
Two methods:
Refresh the view datasources whenever your data is being deleted. You can do this by registering for the NSManagedObjectContextObjectsDidChangeNotification notification and then parsing the userInfo on that notification to see which object was deleted.
Use code similar to below when you're passing data around to multiple threads.
Example:
// Cache and pass the object's ID off to another thread to do work on
// You can just store it as a property on the class
#try {
NSManagedObject *theObject = [managedObjectContext objectWithID:self.theObjectID];
// do stuff with object
}
#catch (NSException * e) {
// An entity with that object ID could not be found (maybe they were deleted)
NSLog(#"Error finding object: %#: %#", [e name], [e reason]);
}
You can check the NSManagedContext is existed when you use the NSManagedObject.
like this:
if (obj.managedObjectContext)
{
//do things
}
You can check [myObject isFault] where myObject is a NSManagedObject instance
You could give a try to use :
shouldDeleteInaccessibleFaults
property on managed object context. As this article says it should change the behaviour of faulting already deleted object.
https://cocoacasts.com/what-are-core-data-query-generations/
Edit:
Since iOS 9 (when it was added) this property default value is YES.
The update action in Grails first checks for the version of the object to be updated and then updates it.
What part of Grails ensures that the object isn't updated by another request during checking the version and updating the object?
Update:
Yes, hibernate will check for the version when savin the object and will throw an exception is optimistic locking fails. And I guess hibernate will make sure that the check+update is atomic, but...
if you take a look at the grails generated update method, you'll find that grails first double-checks and then (from my point of view) isn't prepared to handle the exception. The chances that hibernate will throw an exception after the update method has already checked for the right version are small, but it seems possible to me.
So wouldn't it be enough to try a save and catch the exception (if there is one)?
It's managed by Hibernate layer. It's called 'optimistic locking', and basically it updates only a object with a known version. Like:
UPDATE SET
%... fields ...%,
version = version + 1 --update version to a new value
WHERE
id = %obj id% --current object
AND version = %previous obj version%` --last known version
And throw exception when it fails to update (btw, at this moment it's hard to recover from this error, at most cases you just losing your update).
If you want to be sure that data is saved, try to force data saving (and check for saving/validtion error):
try {
if (!obj.save(flush: true)) {
// validation error
}
} catch (OptimisticLockingFailureException e) {
// not saved
}
or even lock data before update. It's useful only when you have a lot of concurrent updates.
MyDomain obj = MyDomain.lock(params.id) //now it's locked for update
// update fields
obj.save()
See more details about GORM locking at http://grails.org/doc/latest/guide/GORM.html#locking