NSManagedObject changedValues ignoring string value - ios

I have a subclass of NSManagedObject on which there's a "currency" attribute. This attribute is a 3 letters string. When I change it from "USD" to "CAD", and then call changedValues on the object, changedValues returns an empty dictionary. Is that the normal behaviour?
I save the managedObjectContext first, then change the attribute, then call changedValues.
This attribute is: not transient, optional, not indexed, no default value.
EDIT: Thx for the help guys I found a bug in my code. Now it works just fine.

I found a bug in my code. Now it works just fine. ;)
I was using a delegate method to update the object from another viewController. When coming back from that viewController I saved the managedObjectContext in viewWillAppear which basically erased the changedValues.

Do it before you save the context.
NSManagedObject Class Reference
changedValues
Returns a dictionary containing the keys and (new) values of
persistent properties that have been changed since last fetching or
saving the receiver.

Related

Saving Array<NSValue> in CoreData as Transformable Attribute

I have an app using CoreData with an entity that has a Transformable attribute.
The attribute is of type Array.
As these are compliant with NSCoding, I never had any problems saving this entity.
Today, I ran into an issue saving these entities which I never had a problem with in the past.
value for key 'NS.objects' was of unexpected class 'NSValue'
I don't know if a recent update broke this, but all of the sudden I cannot save my entity with the transformable attribute of type Array.
No idea where the problem came from. It has been working for a long time.
Why am I now getting an error trying to access an entity with a transformable attribute of type Array ?
If you just want to save an array of objects (like String), set Custom Class as [String].
You also can set values as [Data], and later get object with decoding it.

Realm inverse relationship returns object with nil properties

I got a class named Team, it has a RLMArray property called players with Player class objects.
When i try to access the team by calling (according to documentation)
[self linkingObjectsOfClass:#"Team" forProperty:#"players"];
on a player object, i get a single team object ( how it's supposed to be ), but all the properties are nil, even primary key.
Has anyone faced the same issue?
It's expected that instance variables of persisted RLMObject instances will be nil as the property getters read values directly from the Realm file. The instance variables are only used for objects prior to being saved to the Realm, and remain nil after that point.
The Debugging section of the Realm documentation touches on this topic and mentions an LLDB script that can be used to show property values of persisted objects when debugging in Xcode. The -description method on the model classes, used by NSLog when formatting objects using the %# format specifier, will also show the property values as expected.

Are ivars of PFObject subclasses stored in local datastore?

I have a subclass of PFObject called Session. This object stores an array of objects as an instance variable. The array contains objects of type Event, which is also a subclass of PFObject. When I call the pinInBackground on the Session object to cache it locally, will this array instance var also get cached? I understand that caching standard PFObjects stores the data dictionary, but what about subclasses?
Based on the comment from #lightice11 above, I realized that this can be achieved by marking instance vars as #NSManaged, and they will be saved in the Parse Local Datastore.
Make sure you've added the #NSManaged tag to the variable.
Parse will then automatically save changes to the variable, but it does not have a default value. This can be solved in many ways, some of which I outlined here.

NSManagedObject's hasChanges is true while changedValues is empty

I am trying to observe individual NSManagedObject changes on NSManagedObjectContextWillSaveNotification:
- (void)managedObjectContextWillSave:(NSNotification *)notification
{
for (NSManagedObject * object in self.mutableObservedManagedObjects)
{
if (object.hasChanges)
{
[self managedObjectWasUpdated:object];
}
}
}
The problem is that hasChanges is true while object.changedValues is empty, thus wrongly (?) triggering managedObjectWasUpdated:.
I'm trying to understand why this is the case and if I should better check object.changedValues.count before calling managedObjectWasUpdated:.
isInserted and isDeleted are both false.
In my experience, if the entity already existed, you loaded it and then you set a value to a property that is equal to its previous value, then the record will be marked as updated, hasChanges will return YES, and changedValues will be empty. When you save the context, what gets updated is a special Core Data column called Z_OPT, which refers to the number of times an entity has been updated. For these situations you can do something like this before saving:
for (NSManagedObject *managedObject in context.updatedObjects.objectEnumerator) {
if (!managedObject.changedValues.count) {
[context refreshObject:managedObject mergeChanges:NO];
}
}
in order to don't even update the Z_OPT value.
I encountered the same issue. Instead of getting the flags, I just checked if changedValues() is empty.
For Swift:
if !managedObject.changedValues().isEmpty {
// Has some changed values
}
From iOS 7 you can also use hasPersistentChangedValues instead of changedValues. I think this performs better.
According to doc, hasChanges will return YES if the receiver has been inserted, has been deleted, or has unsaved changes, otherwise NO.
In your case, you can check isInserted, isUpdated, isDeleted flag to find what happened to your managed object. changedValues only show the properties that have been changed since last fetching or saving the receiver.
Do you have any transient attributes on your entity? I am seeing the behavior you describe, and I've written some test code that shows that modifying a transient attribute causes hasChanges to return true, while changedValues is empty.
You can avoid this behavior by using setPrimitiveValue:forKey: to modify your transient attribute or the equivalent method generated by Core Data (setPrimitiveFoo: for an attribute named foo). You could also implement the transient attribute's setter to do this for you.
When another managed object in relationship to an NSManagedObject has changes, in my observation an NSManagedObject will sometimes, but not always, have an isUpdated of true, while changedValues is empty.
On other occasions, isUpdated is false, and again changedValues is empty.
changedValues being empty seems the correct behavior here. I am unclear what is cause of the variability in isUpdated being true. Having observed this in my production code, I am working on a simple sample project with hope of reproducing this for a bug report to Apple if I can.
To solve my functional problem in my case, I modified my code to automatically set a timestampModified on the parent object in cases where I wanted to ensure that isUpdated was always consistently set to true when these objects in relationship had changed.

NSPredicate in NSFetchedResultsController doesn't use Category's getter

I have an attribute with an int_32 property called seconds. In a category, I restate the property as readonly and override the getter to create it from other properties. The issue is when I use
[NSPredicate predicateWithFormat:#"SELF.seconds > %i"];
The predicate does not work because the getter is not called by the predicate. It is called in my other code just fine, just not in the predicate. Anyone know why this would happen or how to get around this problem? (besides recreating NSFetchedResultsController).
The predicate is converted into SQL and run on the store. It doesn't run any of your code. As such you can only use the stored value in the data store. No transient attributes, no methods.
If you want to use the attribute in a fetch then you should save the value. This could be done by implementing willSave and having it set the value just before any other value changes are saved.

Resources