0

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])
Gil Sand
  • 5,802
  • 5
  • 36
  • 78
  • Did you copy your full predicate? If so, you have to add `%@` for the name field too: `@"compositeName contains[c] %@ OR name contains[c] %@"` – tbaranes Apr 16 '15 at 09:32
  • god damn i hope it's just that, it's missing in my code too. – Gil Sand Apr 16 '15 at 09:33
  • No, it's still crashing but the %@ was missing so thank you :D The exception is very clear, my "User" isn't key-value coding compliant for the key "compositeName". – Gil Sand Apr 16 '15 at 09:33
  • Can you add your crash log? – tbaranes Apr 16 '15 at 09:43
  • Can you combine a class type check (assuming you are using NSManagedObject subclasses) as the first clause in an AND with the name/compositeName - hopefully NSPredicate is optimised so that if the first clause is false it doesn't evaluate the second - http://stackoverflow.com/questions/8065866/nspredicate-check-for-kind-of-object-class – Paulw11 Apr 16 '15 at 09:44
  • that's clever, let me try that. – Gil Sand Apr 16 '15 at 09:45
  • Just tried this but the format isn't correct, do you see a mistake? `@"((className == %@) name contains[c] %@) OR ((className == %@) compositeName contains[c] %@)", @"User",searchText, @"Contact", searchText`. – Gil Sand Apr 16 '15 at 09:51
  • I also edited my answer to reflect our comments. – Gil Sand Apr 16 '15 at 09:59
  • I would think you want something like this `@"(className == %@ AND name contains[c] %@) OR (className == %@ AND compositeName contains[c] %@)",[User className],searchString,[contact classname],searchString` – Paulw11 Apr 16 '15 at 10:01
  • Oh this predicate works :) Thx man ! You can post it as an answer if you want and I'll validate it :) Thank you a lot :) These predicates are really handy but when you don't know the grammar it's so frustrating! – Gil Sand Apr 16 '15 at 10:11

1 Answers1

2

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
Paulw11
  • 108,386
  • 14
  • 159
  • 186