7

I'm making a class, that given an object target, a selector to watch for, and a displayTitle will output a string in this format: @"displayTitle: object.selector". It then registers itself through KVO so that anytime the value of object.selector changes, it can notify a view controller to update the view. I am using this as an abstract and reusable way to show a description of various properties of an object to a user.

When I try to get the value of object.selector, I can't do [object performSelector:selector] because LLVM gives errors when you use performSelector with a dynamic selector. So, I did exactly what this answer suggested: I used 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;
}

And I got an EXC_BAD_ACCESS!

Screenshot

As you can see in the screenshot, I made sure that doing [object selector] works.

What is going on, and how can I fix it?

4

3 回答 3

6

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

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

于 2014-06-15T18:03:08.307 回答
4

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

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

NSInteger value;
NSInteger (*f)(id, SEL) = (NSInteger (*)(id, SEL))objc_msgSend;
value = f(object, selector);
于 2014-06-16T05:00:54.103 回答
3

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

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

如果这是您的问题,只需将您的值包装为NSNumber

于 2014-06-15T18:03:15.903 回答