5

I've only recently noticed a crash in one of my apps when an object tried to message its delegate and the delegate had already been released.

At the moment, just before calling any delegate methods, I run this check:

if (delegate && [delegate respondsToSelector:...]){
   [delegate ...];
}

But obviously this doesn't account for if the delegate isn't nil, but has been deallocated.

Besides setting the object's delegate to nil in the delegate's dealloc method, is there a way to check if the delegate has already been released just incase I no longer have a reference to the object.

Tom Irving
  • 10,041
  • 6
  • 47
  • 63

4 Answers4

16

No. There is no way to tell whether a variable points to a valid object. You need to structure your program so that this object's delegate isn't going away without letting it know first.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • 2
    Thanks. Since the crash it was a simple matter of setting the object's delegate to nil in the delegate's dealloc, but it got me thinking in general :) – Tom Irving Jun 02 '10 at 00:50
8

I assume you're not using GC. In that case, standard convention is that the code that sets the delegate is responsible for setting the delegate-user's reference to nil before allowing the delegate to be deallocated. If you're using GC, you can use a __weak reference for the delegate, allowing the garbage collector to set the reference to nil when the instance is garbage collected.

Barry Wark
  • 107,306
  • 24
  • 181
  • 206
  • +1 for bringing up `__weak` references, and recommending them in the context of GC. In fact, one can argue that using `__weak` in this case is the right thing to do, if (when?) the code is eventually switched to GC in the future. – Quinn Taylor Jun 02 '10 at 01:24
  • still there exist __unsafe_unretained for legacy support, and it is pretty tricky to use as ARC not assign nil value to collected __unsafe_unretained objects. – Gökhan Barış Aker Sep 03 '12 at 08:18
0

for debug proposes you can override release method on your class to see when it is called.

-(oneway void)release
{
    NSLog(@"release called");
    [super release];
}
ademar111190
  • 14,215
  • 14
  • 85
  • 114
0

how about using a counter that you increment everytime you alloc and decrement everytime you dealloc. That way you could detect double allocs and could decide not to use a delegate if the counter isnt nil but the address isnt nil also

yan bellavance
  • 4,710
  • 20
  • 62
  • 93
  • This isn't a good idea, sadly. Objects track their own retain count, which is how they are "automatically" deallocated after the last release. Since he doesn't retain the delegate, this really wouldn't help much anyway. – Quinn Taylor Jun 02 '10 at 01:22
  • yeah that was a long shot but I wanted to describe how referencing and dereferencing is managed in the background on some frameworks – yan bellavance Jun 02 '10 at 16:40
  • After two years what @tom has asked I find it very useful. I came across with the same scenario and the best solution would be to declare my delegate property as 'weak', sadly I need to make it backward compatible (should support iOS 4 deployment targets as well). So my guess is to go with Blocks instead of Delegates pattern, will that work ? (I use delegates to download images in background and invoke the callback of the delegate method once it is completed, I can do the same thing using Blocks as well. Not sure it will resolve the issue behind calling deallocated objects) – chathuram May 07 '12 at 19:09