我正在创建一个类,给定一个对象目标,一个要监视的选择器,displayTitle将以这种格式输出一个字符串:@“displayTitle:object.selector”.然后它通过KVO注册自己,这样只要object.selector的值发生变化,它就可以通知视图控制器更新视图.我使用它作为一种抽象和可重用的方式向用户显示对象的各种属性的描述.
当我尝试获取object.selector的值时,我无法执行[object performSelector:selector]因为LLVM gives errors when you use performSelector with a dynamic selector.
所以,我完全按照this answer的建议做了:我使用了objc_msgSend(对象,选择器).
- (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; }
我得到了一个EXC_BAD_ACCESS!
正如您在屏幕截图中看到的那样,我确保了这一点
做[对象选择器]工作.
发生了什么,我该如何解决?
解决方法
您将objc_msgSend调用的结果分配给类型为id的变量,以便ARC启动并尝试保留结果对象(崩溃在objc_retain中,因为您可以在左侧的堆栈中看到).但是,结果不是对象而是值为8的整数,objc_retain将其作为指针.但是没有这么低的有效指针,所以你得到了EXC_BAD_ACCESS.
只需将值的类型更改为NSUInteger(或任何其他非对象类型).但请确保所有潜在的选择器都返回相同类型的数据.或者,确保始终返回一个可以由ARC保留的对象(或零).