为什么objc_msgSend导致EXC_BAD_ACCESS?

Eli*_*son 6 exc-bad-access objective-c selector objc-message-send

我正在创建一个类,给定一个object目标,一个selector要监视,并且displayTitle将以这种格式输出一个字符串:@"displayTitle: object.selector".然后,它通过KVO寄存器本身,以便任何时候valueobject.selector变化,它可以通知一个视图控制器更新视图.我使用它作为一种抽象和可重用的方式向用户显示对象的各种属性的描述.

当我尝试获取值时object.selector,我无法做到,[object performSelector:selector]因为当您使用带动态选择器的performSelector时,LLVM会出错.所以,我完全按照这个答案提出的建议:我用了objc_msgSend(object, selector).

- (instancetype)initWithSelector:(SEL)selector onObject:(NSObject*)object displayTitle:(NSString*)displayTitle {
    self = [super init];

    if (self) {
        id value;

        if ([object respondsToSelector:selector) {
            // Used objc_msgSend instead of performSelector to suppress a LLVM warning which was caused by using a dynamic selector.
            value = objc_msgSend(object, selector);
        } else {
            return nil;
        }

        [self setItemDescription:[NSString stringWithFormat:@"%@: %@", displayTitle, value]];
    }

    return self;
}
Run Code Online (Sandbox Code Playgroud)

而且我得到了EXC_BAD_ACCESS!

截图

正如您在屏幕截图中看到的那样,我确保这样做[object selector]有效.

发生了什么,我该如何解决?

Rap*_*ert 6

您将objc_msgSend调用的结果分配给一个类型的变量,id以便 ARC 启动并尝试保留结果对象(objc_retain如您在左侧堆栈中看到的那样,发生了崩溃)。然而,结果不是一个对象,而是一个值为 8 的整数,它objc_retain是一个指针。但是没有这么低的有效指针,所以你得到了EXC_BAD_ACCESS.

只需将类型更改valueNSUInteger(或任何其他非对象类型)。但要确保所有潜在的selectors 返回相同类型的数据。或者,确保始终返回一个对象(或nil),它可以由 ARC 保留。