I'm writing iOS apps using ARC and targeting iOS 5+.
Suppose I write a custom view object that has a delegate property. In declaring the delegate property, I make it a weak reference to avoid a retain cycle, so that when the actual delegate object (the controller) is destroyed, my custom view will also be destroyed, as follows:
@interface MyCustomView : UIView
@property (nonatomic, weak) id<MyCustomViewDelegate> delegate;
@end
All is good.
Ok, so now I'm writing the controller object, and it has references to two view objects: my custom view and an Apple-supplied UIKit view, both of which declare delegate properties, and the controller is the delegate for both views. Maybe it looks something like this:
@interface MyViewController : UIViewController <MyCustomViewDelegate, UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) MyCustomView *customView;
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation MyViewController
- (void)viewDidLoad
{
self.customView.delegate = self;
self.tableView.dataSource = self;
self.tableView.delegate = self;
}
@end
My question is this: Do I need to override dealloc to set either or both delegates to nil?
I mean, as I understand it, the delegate property of the UIKit view (in this case, tableView
) isn't actually declared to be a weak reference, but rather an __unsafe_unretained
reference, for backwards compatibility with non-ARC version of iOS. So maybe I need to write
- (void)dealloc
{
_tableView.dataSource = nil;
_tableView.delegate = nil;
}
Now, if I do have to override dealloc, I still don't have to set _customView.delegate = nil
, right? Because that was declared (by me) to be a weak reference, so it should be set to nil automatically upon the destruction of MyViewController
.
But on the other hand, I'm not targeting non-ARC versions of iOS, nor do I intend to. So maybe I don't need to override dealloc at all?
The only reason you would want to explicitly set the
delegate
anddataSource
tonil
is if thecustomView
or thetableView
could out live the view controller. Setting them tonil
would guard against thedelegate
ordataSource
referencing a deallocated object.If the
customView
andtableView
will be deallocated along with the view controller, there is no need to nil out thedelegate
anddataSource
.If the only strong reference to said
tableView
is your soleMyViewController
controller, you don't need to manually setUITableViewDelegate
orUITableViewDataSource
tonil
.The reason is that once the
dealloc
method on yourMyViewController
is called, the tableview will also be destroyed along with the controller (that is, once again, as long as the only reference to it is your sole controllerMyViewController
class).If you have other strong references to this tableview, such as other controllers, it would then be possible that the tableview could then exist longer than the
MyViewController
class. In such a case, it would be necessary to set theUITableViewDelegate
andUITableViewDataSource
tonil
in the dealloc method ofMyViewController
because, as you mentioned, these properties are NOT weak references and will not automatically be set tonil
.However, this sort of situation is pretty rare in my experience though.
Most of the time, I don't worry about setting these to
nil
honestly, but it is a defensive programming practice.See this post also:
In dealloc method set any delegate to nil is needed or not needed
Setting non-weak delegates to nil is generally a good idea unless you know you don't have to. For
UITableView
andUIScrollView
, I've experienced crashes on previous iOS versions with the following steps (it may help to run with zombies enabled):This appears to happen because the scrolling animation is retaining a reference to the view, so the view outlives the VC. It crashes when sending the scroll event.
I've also seen crashes after dismissing a VC containing a
UIWebView
while a request is being loaded, where simply setting the delegate to nil was not sufficient (I think the workaround was to call[webView loadRequest:nil]
).