Core Data predicates?

Discussion in 'iOS Programming' started by ArtOfWarfare, Nov 21, 2011.

  1. ArtOfWarfare, Nov 21, 2011
    Last edited: Nov 21, 2011

    ArtOfWarfare macrumors 604


    Nov 26, 2007
    This code is crashing my app:

    - (void)textViewDidChange:(UITextView *)textView
    	NSFetchRequest *request = [[NSFetchRequest alloc] init];
        request.entity = [NSEntityDescription entityForName:@"Key" inManagedObjectContext:managedObjectContext];
        request.predicate = [NSPredicate predicateWithFormat:@"shortcut IN %@", typeView.text];
    	NSError *error;
        [color="RED"]NSArray *keys = [managedObjectContext executeFetchRequest:request error:&error];[/color]
        for (Key *key in keys)
    		NSLog(@"Checking if %@ is in %@", key.shortcut, typeView.text);
            if ([typeView.text rangeOfString:key.shortcut].location != NSNotFound)
                typeView.text = [typeView.text stringByReplacingOccurrencesOfString:key.shortcut withString:key.character];
    Key is a core data object that has two NSString properties, called "shortcut" and "character". I would like to check, when a textView is changed, whether the text contains the shortcut for any of the keys, and if it does, to replace the shortcut with the character.

    Here's what's logged:

    2011-11-21 13:57:35.780 QuickClip[2123:15803] -[__NSCFString countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x8a88c40
    2011-11-21 13:57:35.783 QuickClip[2123:15803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x8a88c40'
    *** First throw call stack:
    (0x1e71052 0x2002d0a 0x1e72ced 0x1dd7f00 0x1dd7ce2 0x16c231c 0x16c1a68 0x16b458f 0x16b3adc 0x16ae4c6 0x16ae1ae 0x16adf60 0x16add33 0x16ad389 0x16ace20 0x16ac1cd 0x16aa06d 0xac5f 0xaa51 0x64ea 0x183fbf 0x18421b 0x1850f1 0xf3fec 0xf9572 0xf372b 0xe2bc2 0xe30b8 0x2d8a 0xba9d6 0xbb8a6 0xca743 0xcb1f8 0xbeaa9 0x1d5bfa9 0x1e451c5 0x1daa022 0x1da890a 0x1da7db4 0x1da7ccb 0xbb2a7 0xbca9b 0x2aed 0x2a65)
    terminate called throwing an exception(gdb) 
    Suggestions as to what I'm doing wrong?

    Edit: I feel like it's my predicate that isn't working... I've tried changing it to this:
    request.predicate = [NSPredicate predicateWithFormat:@"%@ CONTAINS shortcut", typeView.text];
    but it still doesn't work and I get the same log output...

    2X Edit: After thinking of the output for a bit... it's occurring to me that my idea of "CONTAINS" and "IN" are not the same as what's actually happening...
    for CONTAINS it's looking at the left side object as an array of strings and seeing if any of the strings are equal to the shortcut...
    for IN it's looking at the right side object as an array of strings and seeing if any of the strings are equal to the shortcut...
    thus these just won't work for what I want.

    3X Edit: Alright, I've managed to get this to work by using:
    request.predicate = [NSPredicate predicateWithFormat:@"shortcut LIKE %@", @"*"];
    I'd rather if it was more intelligent and actually only did searched for shortcuts containing the character that was just typed, but, eh, I guess this is good enough.
  2. chown33 macrumors 604

    Aug 9, 2009
    What does the logged exception tell you?

    Break it down.

    Here are the pieces:
    1. Terminating app due to uncaught exception 'NSInvalidArgumentException',
    2. reason: '-[__NSCFString countByEnumeratingWithState:eek:bjects:count:]: unrecognized selector sent to instance 0x8a88c40'
    Part 1 tells you the app is terminating. Because of an NSInvalidArgumentException. That isn't being caught.

    Part 2 tells you the reason you're getting that exception. The fundamental reason is unrecognized selector. There are two possible reasons for that:
    A. You've sent the message to a valid object whose type you've mistakenly thought was something that could receive the message.
    B. You've sent the message to an invalid object. The pointer was dealloc'ed (usually via autorelease pool), and another object of a different type has since been created at the same address, which can't receive the message.
    By far, B is more common.

    So, how can you get an invalid object, whose memory is then reused to create another object? One way: improper ownership. That is, under-retain or over-release. Of those two, under-retain is more common.

    Here's the failure scenario. An object pointer is stored in a variable, but you neglect to retain it. Some time later, it's autoreleased and dealloc'ed. Your pointer is now invalid, but is still stored in a variable. Some time later still, the memory at that address is used to create another object of a different type (a string in this case). Your old variable now has a pointer to a completely different object of a completely different type. You now send it a message (see the exception log) which it doesn't understand. Familiarize yourself with this pattern of behavior, because you'll see it a lot.

    So, how can you diagnose invalid objects that have been dealloc'ed but are still being stored in variables and messaged? Run under instruments with zombies enabled.
  3. jonnymo5 macrumors 6502

    Jan 21, 2008
    Should "typeView.text" be "textView.text"? I see the method takes in variable textView, yet i don't see it being used.
  4. ArtOfWarfare thread starter macrumors 604


    Nov 26, 2007
    I feel like the issue was actually a special variety of A, that having my predicate involve "IN" or "CONTAINS", it expected an NSArray, whereas I actually was hoping it would recognize it was being given NSStrings and look for one string being a substring of the other.

    Documentation on NSPredicates seems to be very poor... in Apple's 33 page PDF on them, they mention a list of all the possible words one could use in them, but then they do a lousy job of explaining what many of the words do.

Share This Page