views:

67

answers:

2

I have a controller with a delegate.

@interface MyConversionController : NSObject {
    id <ConversionDelegate> _delegate;
}
@property (assign) id delegate;
@end    

@implementation
@synthesize delegate = _delegate;
@end

I'm getting Unrecognized selector sent to instance 0x36c4a0 errors. I've set a breakpoint on the -(void)setDelegate(id)delegate method so I can observe objects that are passed into my MyConversionController class. My setDelegate method is called twice, the first time is an object at the address 0x36c4a0 that I know conforms to the <ConversionDelegate> protocol. The second time this method is called another object is passed in that also conforms to the protocol. When the time comes to start calling methods on the delegate the method calls are sent to the first object (0x36c4a0) which is now some other kind of object (usually a CFString or __NSFastEnumerationEnumerator if that makes a difference).

Does anyone know why this could be happening?


After running malloc_history I see that the first address, the one that's giving me trouble, is allocated and freed a number of times before I get to it. The second object is just allocated once. Under what conditions would the pointers be reused like this?

+1  A: 

You might want to use malloc_history to find the callstack of the object at that address. Do the following in the terminal while your process is running:

malloc_history <pid> 0x36c4a0 # insert the address in question for the 2nd arg

You'll also need to enable MallocStackLogging (thanks to Kubi's comment below on this).

This may help you understand where the object at that address is being allocated.


Also, you've marked the delegate as assign, not retain, however, I think this is appropriate for delegates. That said, if it was autoreleased somewhere else, that memory may be being reused.

Are you possibly autoreleasing the delegate and assigning it? Something like:

delegate = [[[ConversionDelegateClass alloc] init] autorelease];
controller.delegate = delegate

If so, the delegate will be released in the next autopool release since nothing is retaining it and that memory location will be available for re-use.

nall
The assign was intentional. My impression was that it's customary for classes to *not* retain any delegates they may have, to avoid class A and class B both retaining each other so that neither ever gets released.Thanks for the malloc_history tip.
kubi
You've got to turn on `MallocStackLogging` for this to work.
kubi
A: 

The problem is that the the delegate was being prematurely deallocated. The reason this was so difficult to debug was that the deallocation occured in code I had written a long time ago, and the program would quit before the issues would occur. Writing the new sliver of code kept the program open for just long enough for other classes to start sending messages to the deallocated object.

Solution: I ran the code with the the Zombie module in Instruments. Wish I had done this a few days ago, I fixed the code within 30 seconds of looking at the output from Instruments.

kubi