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?
Setting non-weak delegates to nil is generally a good idea unless you know you don't have to. For UITableView
and UIScrollView
, I've experienced crashes on previous iOS versions with the following steps (it may help to run with zombies enabled):
- Scroll really fast.
- Press Done or the back button or whatever to dismiss the VC.
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]
).
If the only strong reference to said tableView
is your sole MyViewController
controller, you don't need to manually set UITableViewDelegate
or UITableViewDataSource
to nil
.
The reason is that once the dealloc
method on your MyViewController
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 controller MyViewController
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 the UITableViewDelegate
and UITableViewDataSource
to nil
in the dealloc method of MyViewController
because, as you mentioned, these properties are NOT weak references and will not automatically be set to nil
.
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
The only reason you would want to explicitly set the delegate
and dataSource
to nil
is if the customView
or the tableView
could out live the view controller. Setting them to nil
would guard against the delegate
or dataSource
referencing a deallocated object.
If the customView
and tableView
will be deallocated along with the view controller, there is no need to nil out the delegate
and dataSource
.