views:

921

answers:

4

If class A is using class B and class A is class B's delegate, is it ok if the delegate is set to nil in class B's dealloc? I have seen code usually resetting the delegate to nil inside class A's dealloc but wasn't sure the real difference doing it one way or the other.

e.g. This is the usual way:

// somewhere in class A

- (void) someFunc {
  self.b = [[B alloc] init];
  self.b.delegate = self;
}

- (void) dealloc {
  self.b.delegate = nil;
  [self.b release];
}
+5  A: 

As far as I know, its best practice to (assign) a delegate, such that you avoid circular references on retain counts for situations just like this. If you've set up the property properly, ie:

@property (assign) id<BDelegate> delegate;

You shouldn't have to perform any memory management in the dealloc, as the retain count is not bumped when you call self.b.delegate = self; -- unlike using (retain) or (copy)

Make sense? It would be fine to set the delegate to nil, but whats the point?

Josh
+1 That's correct, delegates should pretty much never be retained. That's a classic cause of retain cycles, since the delegate usually retains the delegating object.
Quinn Taylor
There is a point in setting the delegate to nil because if the client attempts to call a delegate object that no longer exist, it won't crash since it's set to nil.
Boon
You are dealloc'ing the class that contains the delegate... you're removing the instantiation of the class from memory at that point, you're going to get a memory access error if you perform any action on the object, much less refer to its delegate. Unless I am missing something here...
Josh
Yes, you're likely to get an error if this happens, but you can prevent it by setting it to nil. See Peter's answer for a scenario where this can easily happen.
Quinn Taylor
+1  A: 

First, a few observations...

  1. You've forgotten to call [super dealloc] at the end of your own dealloc method.
  2. Since 'a' created 'b', and if no other objects have retained 'b', there no point in nilling the delegate in the -dealloc, since 'b' is about to be destroyed anyhow. If it's possible that other objects have a reference to 'b' (meaning it might outlive 'a') then set the delegate to nil.
  3. Object 'b' should be the one to take care of its delegate in its own -dealloc if necessary. (Generally, the delegator does not retain the delegate.)
  4. Avoid using properties in -init... and -dealloc methods — Apple discourages this, and for good reason. (Not only could it have unexpected side effects, but can also cause nastier, crashier problems.)
  5. Using properties (via the dot syntax) when you don't need to invisibly adds extra work. For instance, self.b.delegate = self is equivalent to [[self getB] setDelegate:self] — it's just syntactic sugar that makes it look like you're accessing the ivar directly, but you're actually not.
  6. Using properties without understanding what they do can lead to trouble. If self.b retains the value (the property is set to "assign"), you have a memory leak on your hands.

Here's how I would probably write it:

- (void) someFunc {
  b = [[B alloc] init];
  b.delegate = self; // or [b setDelegate:self];
}

- (void) dealloc {
  b.delegate = nil;
  [b release];
  [super dealloc];
}
Quinn Taylor
+4  A: 

Yes, you should set the classB's delegate property to nil in classA's dealloc.

It's not a memory management issue, because delegate properties should be marked assign, not retain, to avoid retain cycles (otherwise the dealloc will never be called). The issue is that otherwise classB might message classA after it has been released.

For example, if classB has a delagate call to say "being hidden", and classB is released just after classA, it would message the already dealloc'ed classA causing a crash.

And remember, you can't always guarentee the dealloc order, especial if they are autoreleased.

So yes, nil out the delegate property in classA's dealloc.

Peter N Lewis
+1 Good point about B possibly messaging A. That's most likely in a multi-threaded scenario, but you never know. This is one great application for __weak references if you're using GC. I think delegates should always be __weak in new code.
Quinn Taylor
A: 

According to More iPhone 3 Development by Dave Mark and Jeff LeMarche, setting the delegate property to nil when you're done is good form, but if you fail to do so, it usually won't cause major problems. Although there are a few exceptions in the system, objects generally don't retain their delegates. Failing to set a delegate to nil won't prevent an object's retain count from reaching zero when it is another object's delegate.

Rose Perrone