NSPredicate in NSFetchedResultsController doesn't use Category's getter - ios

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.

Related

How can I make NSFetchedResultsController event correctly when predicate values change?

In my Core Dara model, there is a single Session object that holds a single Order object (though other orders can be floating around in CoreData) and Order holds Purchases. I've got an NSFetchedResultsController that fetches Purchases for the Order in the Session.
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"order.session = %#" argumentArray:#[session];
This works fine for fetching, but it doesn't call back the delegate methods for the fetched results controller in the case that the Order becomes detached from the Session. Is this just a failure in the NSFetchedResultsController, or is there a documented limitation? More importantly, how can I get around that limitation in a clean way?
To be clear, the results controller always returns the correct result after calling performFetch: it's just not firing the delegate methods.
I think this is just a "feature". The fetched results controller tracks changes to its fetched objects, but as far as it's concerned those objects are unchanged - the only change is to the related Order object. I think your best bet would be to use Key Value Observing of your Order object (or Session object) in order to be notified if they become "disconnected".

CoreData overwriting Getter and Predicates

I'm trying to localize my Core Data app. I found different approaches and the one I'm interested most in, is described in this question. Basically it creates a new table and overwrites the getter, to return the correct localization.
entity(Book, title, localizedTitle)
entity(LocalizedString, localization, string)
What I don't get right now, is, if it influences the predicate, too. Usually I would write a predicate like this:
[NSPredicate predicateWithFormat:#"title = %#", someString];
In case the property title is in my CoreData Class via a category overwritten to be localized and someString is a user selection I search for. Does this compare the localized title with someString, or title?
So will the predicate use the overwritten property of title and return localizedTitle to compare it with someString, or will it use the empty title field to compare it to someString?
I had to revoke the answer, since I found out, that when you override a getter, the NSPredicate will use the overridden getter. Some weird behavior, but seems like codeData does this.
The NSPredicate itself is not using any of your code if not inserted by you with the %#. It is a SQLite request inside a wrapper object NSPredicate. With title you are not using your title property (so the getter) in one of your wrapper CoraData Objects for a row in the database. title is only an access to a column in your database, nothing transient.
The customized getter you created is for receiving the data from the database through CoreData, packed each row into a wrapper object subclassed from NSManagedObject. If you access a property of this wrapper object it reads the data and localizes it lazily. So nothing from the data has changed.
I tested this with a little app to make sure!
Maybe we mean different things. I have a subclass of NSManaged Object. This subclass uses a custom getter to change the value of the NSManagedObject from #"butter" to #"milch".
The real value in the SQLite database (and only to make sure with #dynamic), the output is 'butter', but with the custom getter every other class I tried will get 'milch' as the attribute from CoreData except NSPredicate. The attribute is called 'name'. Now I use a NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"name = %#", #"milch"];
It is not using the getter. Since all objects would fulfill that predicate with the custom getter:
- (NSString *)name {
return #"milch";
}
Maybe another stackoverflow answer is more precise:
NSPredicate in NSFetchedResultsController doesn't use Category's getter

NSManagedObject changedValues ignoring string value

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.

Understanding Transient properties with NSFetchedResultsController

I'm starting to create an application with Core Data, to retrieve a data for sectioned table i want to use NSFetchedResultController, in the example from apple there are two additional properties.
primitiveTimeStamp
primitiveSectionIdentifier
For the case of primitiveSectionIdentifier apple says that
In contrast, with transient properties you specify two attributes and
you have to write code to perform the conversion.
because the sectionidentifier is transient property.
But what about the timeStamp ?this attribute is not a transient, why there is a primitiveTimeStamp property ? and why there is explicit setter for timeStamp ?
- (void)setTimeStamp:(NSDate *)newDate {
// If the time stamp changes, the section identifier become invalid.
[self willChangeValueForKey:#"timeStamp"];
[self setPrimitiveTimeStamp:newDate];
[self didChangeValueForKey:#"timeStamp"];
[self setPrimitiveSectionIdentifier:nil];
}
or maybe it's not a actual setter? where is _timeStamp=newDate?
CoreData generates the accessors for you. It generates "public and primitive get and set accessor methods for modeled properties".
So in this case it has generated:
-(NSDate*)timeStamp;
-(void)setTimeStamp:;
-(NSDate*)primitiveTimeStamp;
-(void)setPrimitiveTimeStamp:;
"why there is a primitiveTimeStamp property ?"
The declaration is merely to suppress compiler warnings. ie. If you removed the declaration of the property you'd find a warning on compilation but the code would still run.
Or alternatively you could use [self setPrimitiveValue:newDate forKey:#"timeStamp"];
"why there is explicit setter for timeStamp ?"
This is required since setting the timeStamp requires the 'sectionIdentifier' to be recalculated. This is achieved by setting it no nil and letting the get accessor recalculate it lazily.
"where is _timeStamp=newDate?"
The equivalent of this is essentially done in the auto generated implementation of setPrimitiveTimeStamp.
A quote from the docs:
By default, Core Data dynamically creates efficient public and primitive get and set accessor methods for modeled properties (attributes and relationships) of managed object classes. This includes the key-value coding mutable proxy methods such as addObject: and removes:, as detailed in the documentation for mutableSetValueForKey:—managed objects are effectively mutable proxies for all their to-many relationships.
Note: If you choose to implement your own accessors, the dynamically-generated methods never replace your own code.
For example, given an entity with an attribute firstName, Core Data automatically generates firstName, setFirstName:, primitiveFirstName, and setPrimitiveFirstName:. Core Data does this even for entities represented by NSManagedObject. To suppress compiler warnings when you invoke these methods, you should use the Objective-C 2.0 declared properties feature, as described in “Declaration.”

Fetched Property in core data returning improper count

I have a core data relationship that looks like this
ItemA ->> ItemB
where as itemA has many of itemB. i wanted to use a fetched property that allowed me to grab all associated of itemB that were associated with itemA that had an int32 status property set as "2". So i created a fetched property in the data modeler that had the following:
fetched property: completedItem
predicate: status == 2
destination: itemB
when i first tried it out, i got items back and i thought that was all cool and done, then later i noticed odd behavior and when i looked closer the items that it returned had nothing to deal with actual amount of itemB that was associated with an itemA object. Even weirder is that the return type is NSFaultingMutableArray. Here's a quick example
ItemA has 0 of itemB
a filtered predicate search on the NSSet property ItemA has of ItemB returns 0
the fetched property "completedItem" returns 4 of ItemB
the type it returns is NSFaultingMutableArray
This is just weird in my head right now and really isn't making sense. any ideas?
UPDATE 1:
it appears the fetched property listed here gets all ItemB objects that core data has to offer that matches the predicate, even if it's not associated with the ItemA in question
Here's the answer to this all the weirdness in this issue:
1) The fetched properties indeed were not returning ItemB objects just for ItemA. In order for this to occur, you have to add something like this in the fetched properties predicate
status == 2 AND ItemA == $FETCH_SOURCE
2) From the Fetched Properties documentation:
A fetched property is evaluated lazily, and is subsequently cached.
If objects in the destination entity are changed, you must reevaluate the fetched property to ensure it is up-to-date. You use refreshObject:mergeChanges: to manually refresh the properties—this causes the fetch request associated with this property to be executed again when the object fault is next fired.
so basically use refreshObject:mergeChanges to manually refresh the object to reload the fetched property. you can do this by adding a refresh method or by doing some fancy overriding to the KVC get method inside your subclassed NSManagedObject.
This being said, others here (Rob Booth, Grady Player), have other valid solutions by bypassing fetched properties entirely. While these are faril
Kyle, the problem is that Core Data is trying to be smarter than you. Core Data doesn't want to fill up your memory with all of the object in your datastore if you aren't going to use them. So instead of creating real objects all of the time it creates "Faults". Faults are placeholders for real objects, and when you ask for those objects Core Data goes and populates the objects at that time.
My best guess is that your search on the ItemA.ItemB property isn't realizing the linked objects and so that is why you are getting back a 0 set. If you just did a NSSet *mySet = ItemA.ItemB I'm sure you'd see that mySet contains the correct count of objects. But doing a count on ItemA.ItemB is sending the count message to a Faulted Set and thus returns 0.
When you use your completedItems property CoreData seems to be doing at least something to return you the correct number of objects, but not the actual object data yet.
lets use this terminology:
we have one objectA of ClassA
we have some objects (unnamed) of ClassB
we have added the the ClassB objects to objectA.
objectA is a reference to a subclass of NSManagedObject...
when you call objectA.completeItem, you are asking objectA for the set of ItemB's,
this will work because you are working with one instance in memory.
when you make a new NSManagedObjectContext and perform a fetch in it, it doesn't know anything about your objectA or its relationships, unless you perform a save on objectA's context before you perform a fetch.
Edit:
for you predicate to filter out only the classB objects that are owned by ItemA, you can use a predicate like (assume itemA to be the inverse of your ItemA cpmletedItem relationship)
[NSPredicate predicateWithFormat: #"itemA = %#",itemA];

Resources