views:

297

answers:

3

I have a pointer in an objective-C class that I need to send messages to. The pointer can potentially be anything, so I need to make sure that it will respond to my messages before I send them. Here's the function I'm using to do the checking:

int delegatePreparedForSelector(id delegate, SEL aSelector) {
    if (delegate 
     && [delegate isKindOfClass:[NSObject class]]
     && [delegate respondsToSelector:aSelector]) {
     return YES;
    }
    return NO;
}

The problem is that sometimes the delegate pointer is a struct objc-object * and I get a EXC_BAD_ACCESS bad access error when i send the isKindOfClass message.

Is there a better test i should be using to determine if the delegate will respond to my messages?

+5  A: 

It sounds like your delegate is being disposed of before the call, not that there is anything necessarily wrong with this code.

Also, you can enforce a protocol implementation on the parameter like so: id<MyDelegateProtocol> delegate instead of just using a bare id.

slf
This is the problem. When the delegate is deallocated and set to `nil` it's type is set to that `struct objc_object *` I was seeing in the debugger.
kubi
If the delegate was nil, the above would not crash....
bbum
nil is different than deallocated
slf
A: 

the delegate pointer pointing to type struct objc_object causing a problem is confusing, as all objects in Obj-C are of type (digging into an obj-c object):

struct objc_object
{
    struct objc_class *isa;
    /* extra stuff */
};

the *isa points to a class.. some class. So the object you're setting as a delegate might just not exist or point to bad memory.

pxl
You cannot catch a signal (`EXC_BAD_ACCESS`) using @try.
Nikolai Ruhe
woops. you're right. then he'll just have to bear it out and track down whereever the bug is.
pxl
+6  A: 

Wait, do you really mean the pointer can be anything? Like a void * pointing to a chunk of raw malloc'ed memory, or an objc_object that does not derive from NSObject? If that is really the case then there is no way to make this work safely. It is equivalent to saying "Without dereferencing this pointer how can I know it is safe to dereference?" The only way is to have a priori knowledge that whatever passed it into you did not hand you a bad pointer.

You can try to write some signal handler code to cleanup an EXEC_BAD_ACCESS, but ultimately it will work slowly, poorly, and mask lots of other real bugs. Realistically you either have some constraints on what you are being passed in, or you need to re-architect this part of your project.

Louis Gerbarg