使用ARC时,是否在dealloc中将属性设置为nil?


125

我正在尝试学习iOS 5中的自动引用计数。现在,此问题的第一部分应该很简单:

  1. 它是正确的,我根本使用ARC时需要写在我的dealloc明确释放属性声明?换句话说,这是真的,以下就不是需要一个明确的dealloc的?

    @interface MyClass : NSObject
    @property (strong, nonatomic) NSObject* myProperty;
    @end
    
    @implementation MyClass
    @synthesize myProperty;
    @end
  2. 我的下一个更重要的问题来自“ 过渡到ARC发行说明”文档中的一行:

    您不必(实际上不能)释放实例变量,但是您可能需要在系统类和未使用ARC编译的其他代码上调用[self setDelegate:nil]。

    这就引出了一个问题:我怎么知道哪些系统类没有用ARC编译?什么时候应该创建自己的dealloc并将显着保留的属性显式设置为nil?我是否应该假设属性中使用的所有NS和UI框架类都需要显式的dealloc?

关于SO和其他方面的大量信息,涉及使用手动引用跟踪时释放属性支持ivar的做法,但是使用ARC时,有关此信息的信息很少。

Answers:


197

简短的回答:不,您不必dealloc在ARC中取消属性。

长话大说dealloc即使在手动内存管理中,也永远不要放弃in的属性。

在MRR中,您应该释放ivars。删去属性意味着调用设置器,这些设置器可能会调用它不应该输入的代码dealloc(例如,如果您的类或子类覆盖了设置器)。同样,它可能会触发KVO通知。相反,释放ivar可以避免这些不良行为。

在ARC中,系统会自动为您释放任何ivars,因此,如果您仅此而已,则无需实施dealloc。但是,如果您有任何需要特殊处理的非对象ivar(例如,需要使用已分配的缓冲区free()),则仍然必须处理dealloc

此外,如果您已将自己设置为任何对象的委托,则应取消设置该关系dealloc(这是关于调用的内容[obj setDelegate:nil])。关于在未使用ARC编译的类上执行此操作的说明是针对弱属性的。如果该类显式地将其delegate属性标记为,weak那么您不必这样做,因为弱属性的性质意味着它将为您淘汰。但是,如果标记了该属性assign,则应将其标记为dealloc,否则该类将留下一个悬空的指针,并且在尝试向其委托传递消息时可能会崩溃。请注意,这仅适用于非保留关系,例如委托。


2
这很有道理!不过,让我问你一个问题:我有一个常见的情况,就是我有一个MyController : UIViewController创建并拥有UIView 的类,并且还将视图的委托设置为其自身。它是该视图的唯一保留所有者。当控制器被取消分配时,视图也应被取消分配。那么委托指针是否悬空有关系吗?
Emfurry

4
@emfurry:可能不会,因为在您的视图控制器去世时,视图本身不应该位于视图层次结构中,也不应做任何事情,但是最好不要做假设。如果视图异步安排了稍后要执行的工作,并且视图本身最终在短时间内失去了其视图控制器的支持(例如,由于异步工作暂时保留了视图),该怎么办?为了安全起见,最好只取消代表。实际上,如果所讨论的视图是a UIWebView,则文档明确声明您需要取消委托。
莉莉·巴拉德

3
@zeiteisen:No. unsafe_unretained完全等同于一个assign属性,并且是MRR下代表关系的正常行为,需要消除这些关系。
莉莉·巴拉德

4
我不同意关于在MRC的dealloc中不使用setter的声明。苹果公司不推荐这样做,但是他们也在代码中这样做。您实际上可以通过不使用设置器来创建新问题。关于它有几个大讨论。重要的是正确编写setter(如果将其传递为nil值,则它必须表现正确),有时还要注意释放的顺序。
苏珊(Sulthan)2012年

7
@Sulthan:是否在dealloc中使用setter是一大堆蠕虫,但是我的立场基本上可以归结为:您希望在dealloc中调用尽可能少的代码。设置员倾向于通过覆盖子类或通过KVO或其他机制来包含副作用。应该特别避免像瘟疫那样在解除分配方面产生副作用。如果可以从dealloc中删除方法调用,则应该这样做。这可以简化为:不要在dealloc中调用setter。
莉莉·巴拉德

2

只是给出相反的答案...

简短的回答:不,您不必取消deallocARC下的自动综合属性。而且您无需为中的设置使用设置器init

长答案:即使在ARC下,您也应该取消in中的自定义综合属性dealloc。并且您应该对中的那些使用setter init

关键是自定义合成的属性对于无效应该是安全且对称的。

计时器的可能设置器:

-(void)setTimer:(NSTimer *)timer
{
    if (timer == _timer)
        return;

    [timer retain];
    [_timer invalidate];
    [_timer release];
    _timer = timer;
    [_timer fire];
}

滚动视图,表视图,Web视图,文本字段,...的可能的设置方法:

-(void)setScrollView:(UIScrollView *)scrollView
{
    if (scrollView == _scrollView)
        return;

    [scrollView retain];
    [_scrollView setDelegate:nil];
    [_scrollView release];
    _scrollView = scrollView;
    [_scrollView setDelegate:self];
}

KVO属性的可能设置方法:

-(void)setButton:(UIButton *)button
{
    if (button == _button)
        return;

    [button retain];
    [_button removeObserver:self forKeyPath:@"tintColor"];
    [_button release];
    _button = button;
    [_button addObserver:self forKeyPath:@"tintColor" options:(NSKeyValueObservingOptions)0 context:NULL];
}

然后,你不必复制任何代码deallocdidReceiveMemoryWarningviewDidUnload,...和你的财产能安全地予以公开。如果您担心要淘汰中的属性dealloc,那么可能是时候再次检查您的二传手了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.