【问题标题】:Do I set properties to nil in dealloc when using ARC?使用 ARC 时是否在 dealloc 中将属性设置为 nil?
【发布时间】:2011-12-15 22:45:08
【问题描述】:

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

  1. 我确实需要写明确的,这对吗? 使用 ARC 时我的 dealloc 中的 release-property 语句?其他 话,以下是真的 NOT 需要明确 解除分配?

    @interface MyClass : NSObject
    @property (strong, nonatomic) NSObject* myProperty;
    @end
    
    @implementation MyClass
    @synthesize myProperty;
    @end
    
  2. 我的下一个更重要的问题来自Transitioning to ARC Release Notes 文档中的一行:

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

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

在 SO 和其他地方有大量关于在使用手动引用跟踪时释放属性的支持 ivar 的做法的信息,但在使用 ARC 时这方面的信息相对较少。

【问题讨论】:

    标签: objective-c ios automatic-ref-counting


    【解决方案1】:

    简答:不,您不必在 ARC 下清除 dealloc 中的属性。

    长答案:您永远不应该将dealloc 中的属性归零,即使在手动内存管理中也是如此。

    在 MRR 中,您应该发布您的 ivars。取消属性意味着调用 setter,这可能会调用它不应该在 dealloc 中触及的代码(例如,如果您的类或子类覆盖了 setter)。同样,它可能会触发 KVO 通知。释放 ivar 可以避免这些不良行为。

    在 ARC 中,系统会自动为您释放任何 ivars,因此如果您只这样做,您甚至不必实现 dealloc。但是,如果您有任何需要特殊处理的非对象 ivars(例如,您需要分配给 free() 的缓冲区),您仍然需要处理 dealloc 中的那些。

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

    【讨论】:

    • 这是有道理的!让我问你这个问题:我遇到的一个常见情况是我有一个 MyController : UIViewController 类,它创建并拥有一个 UIView 并将视图的委托设置为自身。它是该视图的唯一保留所有者。当控制器被解除分配时,视图也应该被解除分配。那么委托指针是否悬空是否重要?
    • @emfurry:可能不会,因为当你的视图控制器死掉时,视图本身不应该在视图层次结构中,也不应该做任何事情,但最好不要做出假设.如果视图异步安排了稍后完成的工作,并且视图本身最终比它的视图控制器寿命短了一段时间(例如,由于异步工作暂时保留了视图)怎么办?为了安全起见,最好只取消代表。事实上,如果有问题的视图是 UIWebView,文档明确声明您需要取消委托。
    • @zeiteisen: 否。unsafe_unretained 完全等同于 assign 属性,是 MRR 下委托关系的正常行为,需要取消。
    • 我不同意 MRC 在 dealloc 中不使用 setter 的说法。苹果不推荐它,但他们也在他们的代码中这样做。您实际上可以通过不使用设置器来创建新问题。有几个关于它的大讨论。重要的是正确编写 setter(如果您传递一个 nil 值,它必须正确运行),有时还要注意释放的顺序。
    • @Sulthan:是否在 dealloc 中使用 setter 是一大堆麻烦事,但我的立场基本上可以归结为:你想调用 尽可能少的代码在交易中。 Setter 倾向于包含副作用,或者通过在子类中覆盖,或者通过 KVO,或其他机制。像瘟疫一样,应该特别避免 dealloc 中的副作用。如果您可以从 dealloc 中删除方法调用,则应该这样做。这被简化为:不要在 dealloc 中调用 setter。
    【解决方案2】:

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

    简短回答:不,您不必在 ARC 下清除 dealloc 中的自动合成属性。而且你不必为init 中的那些人使用setter。

    长答案:您应该dealloc 中消除自定义综合属性,即使在 ARC 下也是如此。你应该为init中的人使用setter。

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

    一个可能的计时器设置器:

    -(void)setTimer:(NSTimer *)timer
    {
        if (timer == _timer)
            return;
    
        [timer retain];
        [_timer invalidate];
        [_timer release];
        _timer = timer;
        [_timer fire];
    }
    

    scrollview、tableview、webview、textfield、...的可能设置器:

    -(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 中的 nil out 属性,那么可能是时候再次检查您的设置器了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-13
      • 2016-05-06
      • 2013-04-27
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多