Why is objc_msgSend causing an EXC_BAD_ACCESS?

瘦欲@ 提交于 2019-12-10 13:28:35

问题


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!

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?


回答1:


You assign the result of your objc_msgSend call to a variable of type id so ARC kicks in and tries to retain the resulting object (crash is in objc_retain as you can see in the stack to the left). However, the result isn’t an object but an integer of value 8, which objc_retain takes to be a pointer. But there are no valid pointers this low, so you get the EXC_BAD_ACCESS.

Just change the type of value to be NSUInteger (or any other non-object type). But make sure all potential selectors return data of the same type. Alternatively, make sure to always return an object (or nil), which can be retained by ARC.




回答2:


Could it be that your value is 8, an Integer?

Thanks to arc, value is attempted to be retained, i.e. retain at adress 0x8, which would explain that EXC_BAD_ACCESS, 0x8 being a protected address.

If that is your problem, just wrap your value as a NSNumber




回答3:


Just like with calling a function in C, in order to call a method in Objective-C, you need to know the exact type signature of the method.

When you use objc_msgSend and related functions, you need to cast it to the correct function pointer type before calling it. From the other answers and comments, it appears that your method takes no parameters and has return type NSInteger. In that case, in order to use it, you must do something like:

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


来源:https://stackoverflow.com/questions/24232434/why-is-objc-msgsend-causing-an-exc-bad-access

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!