简体   繁体   English

在ARC下将代表设置为nil?

[英]Set delegates to nil under ARC?

I'm writing iOS apps using ARC and targeting iOS 5+. 我正在使用ARC编写iOS应用程序,并以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. 好的,现在我正在编写控制器对象,它引用了两个视图对象:我的自定义视图和Apple提供的UIKit视图,两者都声明了委托属性,控制器是两个视图的委托。 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? 我的问题是:我是否需要覆盖dealloc将其中一个或两个委托设置为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. 我的意思是,据我所知,UIKit视图的委托属性(在本例中为tableView )实际上并未声明为弱引用,而是__unsafe_unretained引用,以便向后兼容非ARC版本的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? 现在,如果我必须覆盖dealloc,我仍然不必设置_customView.delegate = nil ,对吗? Because that was declared (by me) to be a weak reference, so it should be set to nil automatically upon the destruction of MyViewController . 因为(由我)声明它是一个弱引用,所以它应该在MyViewController销毁时自动设置为nil。

But on the other hand, I'm not targeting non-ARC versions of iOS, nor do I intend to. 但另一方面,我不是针对iOS的非ARC版本,我也不打算这样做。 So maybe I don't need to override dealloc at all? 所以也许我根本不需要覆盖dealloc?

Setting non-weak delegates to nil is generally a good idea unless you know you don't have to. 将非弱代表设置为nil通常是个好主意,除非你知道你没有必要。 For UITableView and UIScrollView , I've experienced crashes on previous iOS versions with the following steps (it may help to run with zombies enabled): 对于UITableViewUIScrollView ,我在之前的iOS版本上遇到过以下步骤的崩溃(它可能有助于在启用僵尸的情况下运行):

  1. Scroll really fast. 滚动得非常快。
  2. Press Done or the back button or whatever to dismiss the VC. 按完成或后退按钮或其他任何以关闭VC。

This appears to happen because the scrolling animation is retaining a reference to the view, so the view outlives the VC. 这似乎是因为滚动动画保留了对视图的引用,因此视图比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] ). 在加载请求时解雇包含UIWebView的VC后,我也看到了崩溃,其中简单地将委托设置为nil是不够的(我认为解决方法是调用[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 . 如果对所述tableView的唯一引用是您唯一的MyViewController控制器,则无需手动将UITableViewDelegateUITableViewDataSource设置为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). 原因是一旦调用MyViewController上的dealloc方法,tableview也将与控制器一起被销毁(也就是说,只要对它的唯一引用是你唯一的控制器MyViewController类,它就会再次被销毁)。

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. 如果您对此tableview有其他强引用,例如其他控制器,那么tableview可能会比MyViewController类存在更长时间。 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 . 在这种情况下, 必要对设置UITableViewDelegateUITableViewDataSourcenil在dealloc方法MyViewController因为,正如你提到的,这些性能并不弱引用并不会被自动设置为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. 大多数时候,我并不担心将这些设置nil ,但这是一种防御性编程实践。

See this post also: 也看到这篇文章:

In dealloc method set any delegate to nil is needed or not needed 在dealloc方法中,需要或不需要任何委托为nil

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. 您希望将delegatedataSource显式设置为nil的唯一原因是,如果customViewtableView可以使视图控制器customView Setting them to nil would guard against the delegate or dataSource referencing a deallocated object. 将它们设置为nil将防止delegatedataSource引用解除分配的对象。

If the customView and tableView will be deallocated along with the view controller, there is no need to nil out the delegate and dataSource . 如果将与视图控制器一起取消分配customViewtableView ,则无需将delegatedataSource取消。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM