为什么objc_msgSend导致EXC_BAD_ACCESS?

时间:2014-06-15 17:52:40

标签: objective-c selector exc-bad-access objc-message-send

我正在上课,给定object目标,selector要注意,displayTitle将输出以下格式的字符串:@"displayTitle: object.selector" 。然后它通过KVO注册自己,这样只要value的{​​{1}}发生变化,就可以通知视图控制器更新视图。我使用它作为一种抽象和可重用的方式向用户显示对象的各种属性的描述。

当我尝试获取object.selector的值时,由于LLVM gives errors when you use performSelector with a dynamic selector,我无法object.selector。 所以,我完全按照this answer的建议行事:我使用了[object performSelector:selector]

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

Screenshot

正如您在屏幕截图中看到的那样,我确保了这一点 做EXC_BAD_ACCESS有效。

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

3 个答案:

答案 0 :(得分:4)

您将objc_msgSend调用的结果分配给id类型的变量,以便ARC启动并尝试保留生成的对象(崩溃位于objc_retain,如您所见堆栈向左)。但是,结果不是对象而是值为8的整数,objc_retain将其作为指针。但是没有有效的指针,所以你得到EXC_BAD_ACCESS

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

答案 1 :(得分:3)

你的值是8,是一个整数?

由于arc,尝试保留值,即保留在地址0x8,这可以解释EXC_BAD_ACCESS,0x8是受保护的地址。

如果这是您的问题,请将您的值换成NSNumber

答案 2 :(得分:3)

就像在C中调用函数一样,为了调用Objective-C中的方法,您需要知道方法的确切类型签名。

使用objc_msgSend及相关函数时,需要在调用之前将其强制转换为正确的函数指针类型。从其他答案和注释中可以看出,您的方法没有参数,并且返回类型为NSInteger。在这种情况下,为了使用它,您必须执行以下操作:

NSInteger value;
NSInteger (*f)(id, SEL) = (NSInteger (*)(id, SEL))objc_msgSend;
value = f(object, selector);