'NSInvalidArgumentException', reason: 'Unsupported predicate (null)' - ios

I am getting this Unsupported predicate error, while trying to instantiate a
NSFetchedResultsController with an aggregate Predicate.
My Coredata structure looks like this - There is a PurchaseDetails Entity which has n number of Payment Entity (One to many relationship). Each Payment has a type, for eg.Cash, Cheque , Other etc. Now I need to get the list of all the PurchaseDetails where Payment.type = Cash.
The NSPredicate looks like this: #"ALL payments.type = 'cash'"
Are we not supposed to use ALL ?
The predicate isn't crashing on creation rather it crash while executing the fetch request.
But the same fetch request works fine when used separately without using a NSFetchedResultsController. They both wont work together ?

Yes you need to use ALL if payments is a to-many relationship. Note that this means that every single payment's type will be #"cash". If you just want at least one cash payment, use ANY.
The (null) in the error message hints at something else though. Did you attach the predicate to the fetch request?
Also, did you try to set cache:nilin your fetched results controller? The FRC could be the reason you get stale results.

Related

swift core data get objects from one to many relation

I have two entities and a simple one to many relation, Activity and CountedObject entities, and the relation Counted object can have multiple Activities
So in my code I was able to get the list of counted objects and now I want to calculate the sum of amount from activities related to specific counted object. Here is my code
let countedObject = countedObjects[indexPath.row]
let activities = countedObject.activities?.allObjects as! [Activity]
the problem is when I try to get activities I have an error
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CountedObject activities]: unrecognized selector sent to instance 0x60000009d470'
Seems like the relation is not correct or something
To set relation correctly in CoreData just making relationship in table is not enough you have to set all relation object using an object ex.
countedObject.activity = activityObject
Then after you can access activityObjects from countedObject.activites

Is it possible to include a [NSPredicate predicateWithBlock:] in a NSCompoundPredicate? [duplicate]

I am playing with an app that uses Core Data and NSManagedObjects to populate a UITableView. There is only one class in my application, called Event. I have created the following custom instance method on Event:
- (BOOL)isExpired {
return ([[self.endOn dateAtEndOfDay] timeIntervalSinceNow] < 0);
}
I would like to limit the UITableView that displays Event objects to only the Events that are expired - that is, where isExpired returns YES. I have tried to do this by adding an NSPredicate to the NSFetchRequest:
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary * bindings) {return([evaluatedObject isExpired]);}];
[fetchRequest setPredicate:predicate];
but I get the error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Problem with subpredicate BLOCKPREDICATE(0x272ac)'
***. Does this mean that you can't use a block predicate with an NSFetchRequest? Or have I just constructed it improperly?
Thank you!
So, it appears that we've established in the comments to the original post that this is likely caused by SQLite stores being incompatible with block predicates, since Core Data cannot translate these to SQL to run them in the store (thanks, JoostK).
There might be a couple of ways to overcome this:
Provided that the end date of your entities is a regular attribute, you might be able to express the expiry constraint as a predicate format string instead of a block predicate, which Core Data should be able to translate into a SQL clause.
If the above is possible, you will probably prefer to use a fetch request template to retrieve the expired items. You would need to pass in a substitution variable like $NOW to give access to the current date, though. This has the advantage of making the predicate template show up in the model editor.
Both approaches, however, have the disadvantage of duplicating existing functionality (i.e., your isExpired method). So another way would be fetch all qualifiying entities regardless of their expiry state first, and then run a dedicated filtering step on the resulting set of entities to weed out the non-expired ones. Since by that point, they have been fully resurrected from the store, you should be able to use a block predicate for this.
You can do a normal fetch request without specifying the predicate, and afterwards filter the resulting array:
NSArray *allEvents = [context executeFetchRequest:fetchRequest];
if (!allEvents) { // do error handling here
}
NSArray *expiredEvents = [allEvents filteredArrayUsingPredicate:predicate];

Search in array of different objects

I'm struggling with my predicate search here, probably a lack of vocabulary.
I have a (kind of) weak design here that my deadline doesn't allow me to change too deeply, and the situation is the following.
I'm searching in a tableview of contacts AND users, my two objects of concern here. The search works fine when there are only contacts (and none of the objects listed are users).
Now if it so happens (which it will, very often) that some of these contacts are users, when I search the tableview, my predicate key doesn't match, and I obviously get an exception.
How could I proceed to go around this, knowing I would like the search to still include everyone. (I have a backup plan where I just remove the users from the search feature and it works like a charm).
I tried using the OR in my predicate, like so :
#"compositeName contains[c] %# OR name contains[c] %#" //(where %# is my search string)
but it's not enough to skip the fact that my contact has a "compositeName" and my user has a "name", which causes an exception.
I don't want to modify the key name of my users to "compositeName" because it would imply to reinstall the app for all my beta testers, which is (due to deadlines and app-generated content) also not possible. Unless there is a way for them to have the new data model without having to reinstall, then I would do that and simply call them all "compositeName". (or "name").
I'm using core data and the array is full of NSManagedObject (of user & contact types).
Any idea?
EDIT 1 : Is this a good idea?
I'm thinking of splitting the arrays if there are users, then using different predicates in both, then finally combine them again and show those results. But it seems like a lot of processing and maybe there is something more efficient?
EDIT 2: Crash log
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]: the entity User is not key value coding-compliant for the key "compositeName".'
EDIT 3 : Class check
According to comments and other posts on stack, you can actually add a condition check, and also do class checks in predicate. Now I tried to combine both by writing this :
#"((className == %#) name contains[c] %#) OR ((className == %#) compositeName contains[c] %#)", #"User",searchText, #"Contact", searchText
which isn't a correct format. This is the first time i'm playing with predicates so if you have any clue how to write a predicate that says
(If class = User, then name contains [c], if class = Contact, then compositeName contains [c])
Your issue is that your combined predicate is going to send valueForKey for both of the properties to each object - and a given object only supports 1 of the two properties, so you get the exception.
If you combine an object class test using an AND with the name/compositeName test you can avoid this issue - by testing the class first, the predicate will skip the second test (for name/compositeName) because the first test has already returned false - making it pointless checking the second clause of the AND.
You can use a predicate something like
#"(className == %# AND name contains[c] %#) OR (className == %# AND compositeName contains[c] %#)",[User className],searchString,[Contact classname],searchString

Using NSPredicate for efficient PFQuery

My app is using Parse as a back end. At some point in the app, i have to query objects that should contain at least one of the tags in another array. To make it clear, in the database i have a class Pictures which has a Tags property that saves tags in an array. In my app, i have an array of tags that i need to compare with. Only the objects that has at least one of the tags stored in the Tags property should be fetched. I tried to using the following PFQuery functions whereKey:containedIn: and whereKey:containsAllObjectsInArray: however none of them does what i want. Now i shifted my attention to NSPredicates. I tried the following:
PFQuery *postsQuery = [PFQuery queryWithClassName:#"Pictures" predicate:[NSPredicate predicateWithFormat:#"ANY Tags MATCHES ANY ", _tags]];
When i run the code i receive the following error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "ANY Tags MATCHES ANY "'
How can i perform such a query or the right NSPredicate for my situation?
As an illustration on what the query should be about for further explanation:
let's say one of the objects in the database has the following in the "Tags" column
Tags = ["music", "video", "picture", "chocolate"]
and the tag array that i want to use in predicate is the following:
tagsArray = #["picture", "French"];
what i'm expecting is receiving the previous object because it has the "picture" tag. If another object doesn't contain at least one of the tags in the tagsArray it shouldn't be fetched.
Edite:
I found out that i can't use Aggregate Operations such as ANY, SOME, ALL, or NONE. could i find another solution?
The other solution is to use cloud code and write the query on the server in Javascript.
Then you just access the new API endpoint that you defined and get the results of the query that way.
Okay, i found out that using whereKey:ContainedIn: actually works out in this case. My problem that i was passing by mistake an array of dictionaries. The one i wanted to use is made of strings.
This is an example of how to use NSPredicate
in swift 4
let predicate1 = "\(PFUser.current()!.objectId!)\(userObj.objectId!)"
let predicate2 = "\(userObj.objectId!)\(PFUser.current()!.objectId!)"
let predicate = NSPredicate(format:"\(CHATS_ID) = '\(predicate1)' OR \(CHATS_ID) = '\(predicate2)' ")
let query = PFQuery(className: CLASS_NAME, predicate: predicate)

NSManagedObjectContext -save: crashes when using NSPredicate

I have a search bar and some filters in my app that create two predicates. One for the string in the search bar and one for the filter (UISegmentedControl).
When the predicates are used and I insert one object into the context and then call -save: the app crashes with:
CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. Can't use in/contains operator with collection 1379410732 (not a collection) with userInfo (null)
at the point of saving:
This does not happen when the predicates are not used.
Can I somehow remove the predicates during the process of saving? I already tried it by getting the NSFetchRequest, but I cannot set it back to the controller then.
Edit
I also tried to add self as an observer on the NSManagedObjectContextDidSaveNotification and then use -mergeChangesFromContextDidSaveNotification: like one discussion on SO suggested. This didn't help either.
I found my problem. It was quite easy, but the error message was so confusing that I didn't look at the right point.
The problem was that I was using [NSPredicate predicateWithFormat:#"number CONTAINS[cd] %#", string].
So the predicate was using CONTAINS on a NSNumber. The confusing part is that the predicates are working when querying existing data from the database. I still don't understand this part, but it's working now with == comparator.

Resources