为什么 iOS 会尝试在 NSIndexPath 上调用 rangeOfCharacterFromSet:?

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

我收到以下错误,导致 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

看起来像 iOS 正在尝试将消息发送到 NSString 选择器,但消息已发送到 NSIndexPath。奇怪!

后来我发现了问题;我将 UILabel 中文本的值设置为指向 CoreData 对象的 NSNumber 列 (0xc000000000000016) 中对象的指针,而不是 NSString。在将它传递给我的 enumToString: 方法之前,我的修复已添加 .intValueNSNumber

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;
}

这就留下了问题:为什么这会导致 iOS 尝试向不存在的选择器 -[NSIndexPath rangeOfCharacterFromSet:] 发送消息?

崩溃发生在刚完成 -[UITableViewDataSource tableView:cellForRowAtIndexPath:]

好的,所以原因很可能不是某些线程出错。核心数据在某些时候将 NSManagedObjects 变成错误。这可能是相关的。此外,NSNumbers 是一种特殊的对象:指针是一个带标签的指针,这个带标签的指针可能包含实际的数值。这可能也有关系。无论如何,一条消息被发送到一个指针,而该指针不再指向识别该消息的对象。在此处阅读有关标记指针的信息:https://www.mikeash.com/pyblog/friday-qa-2012-07-27-lets-build-tagged-pointers.html