Search code examples
objective-ccore-foundationunrecognized-selector

Why would iOS try to call rangeOfCharacterFromSet: on an NSIndexPath?


I'm getting the following error, which causes a SIGABRT:

2015-09-10 17:54:23.859 MyApp[1310:2027719] ERROR CRASH #(null) -[NSIndexPath rangeOfCharacterFromSet:]: unrecognized selector sent to instance 0xc000000000000016
2015-09-10 17:54:23.879 MyApp[1310:2027719] ERROR Stack Trace: (
    0   CoreFoundation                      0x0000000183840248 <redacted> + 160
    1   libobjc.A.dylib                     0x00000001952640e4 objc_exception_throw + 60
    2   CoreFoundation                      0x00000001838472f4 <redacted> + 0
    3   CoreFoundation                      0x00000001838440a8 <redacted> + 928
    4   CoreFoundation                      0x000000018374696c _CF_forwarding_prep_0 + 92
    5   UIKit                               0x0000000188632a44 <redacted> + 104
    6   UIKit                               0x00000001887a0ff0 <redacted> + 76
    7   UIKit                               0x00000001887a10b0 <redacted> + 56
    8   UIKit                               0x00000001887a1194 <redacted> + 36
    9   QuartzCore                          0x0000000187bf0820 <redacted> + 320
    10  QuartzCore                          0x0000000187bf06c4 <redacted> + 32
    11  QuartzCore                          0x0000000187befe58 <redacted> + 276
    12  QuartzCore                          0x0000000187befbd8 <redacted> + 528
    13  QuartzCore                          0x0000000187be9300 <redacted> + 80
    14  CoreFoundation                      0x00000001837f7ff0 <redacted> + 32
    15  CoreFoundation                      0x00000001837f4f7c <redacted> + 360
    16  CoreFoundation                      0x00000001837f535c <redacted> + 836
    17  CoreFoundation                      0x0000000183720f74 CFRunLoopRunSpecific + 396
    18  GraphicsServices                    0x000000018d0436fc GSEventRunModal + 168
    19  UIKit                               0x0000000188322d94 UIApplicationMain + 1488
    20  MyApp                               0x00000001000437b0 main + 68
    21  libdyld.dylib                       0x000000019590ea08 <redacted> + 4

which looks like iOS is trying to send a message to an NSString selector, but the message was sent to an NSIndexPath. Weird!

I've since found the problem; I'd set the value of the text in a UILabel to be a pointer to an object in a CoreData object's NSNumber column (0xc000000000000016) instead of an NSString. My fix was added .intValue to the NSNumber before passing it to my enumToString: method.

typedef NS_ENUM(NSInteger, MyEnum)
{
    MyEnum1 = 1,
    MyEnum2,
    MyEnum3
};

- (NSString*)enumToString:(MyEnum)enumValue
{
    switch (enumValue) {
        case MyEnum1:
            return @"One";

        case MyEnum2:
            return @"Two";

        case MyEnum3:
            return @"Three";
    }
}

- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCell"];
    // cdObject is a managed object in CoreData. Its enumValue column is an NSNumber.
    cell.textLabel.text = [self enumToString:cdObject.enumValue];
    return cell;
}

This just leaves the question: Why would this cause iOS to try to send a message to the non-existant selector -[NSIndexPath rangeOfCharacterFromSet:]?

The crash occurred just after completing a -[UITableViewDataSource tableView:cellForRowAtIndexPath:]


Solution

  • Ok, so the cause is most likely not some threading gone wrong. Core Data turns the NSManagedObjects into faults at some point. This might be related. Also, NSNumbers are kind of special objects: the pointer is a tagged pointer, and this tagged pointer might contain the actual numeric value. This might also be related. In any case, a message was sent to a pointer, and that pointer no longer points to an object that recognizes that message. Read here about tagged pointers: https://www.mikeash.com/pyblog/friday-qa-2012-07-27-lets-build-tagged-pointers.html