释放属性的简单模式

Posted

技术标签:

【中文标题】释放属性的简单模式【英文标题】:Easy pattern for releasing properties 【发布时间】:2011-08-20 09:46:56 【问题描述】:

我有一个关于属性内存管理的一般性问题。目前,我总是使用没有任何明确声明相关 ivars 的属性。而且,对于每个保留或复制的属性,我都会在 dealloc 和 viewDidUnload 方法中释放其保留计数:

-(void)dealloc
  [self.myProperty release];
  [self.myOutlet release];
  [super dealloc];


- (void)viewDidUnload
  [super viewDidUnload];
  self.myProperty = nil;
  self.myOutlet = nil;

现在,我知道只有主视图保留的outlets和property应该在viewDidUnload中设置为nil,其余的属性应该在dealloc中释放。但是,嘿,为什么我必须为必须释放它的每个属性而烦恼——在 dealloc 中还是在 viewDidUnload 中?如果某个属性将被释放两次,那没关系,因为它不会通过向 nil 对象发送消息来使应用程序崩溃。将 release 放在两个地方(dealloc 和 unload)可以节省时间并防止以后在进行代码重构和忘记更改发布位置时出现错误。有任何批评者和大喊大叫吗? :)

【问题讨论】:

【参考方案1】:

如果您因为无法直接访问 ivar 而在 -dealloc 中使用属性访问器,则应该在 -dealloc 中执行与 -viewDidUnload 中相同的操作:

self.myProperty = nil;

在 -dealloc 中使用 -release 的目的是避免调用访问器,当子类中的其他所有内容都已经完成时,可能会被子类覆盖以产生您不希望在 -dealloc 中出现的副作用被解除分配。但是如果你已经在 -dealloc 中调用了访问器,你不妨使用 setter 来释放 ivar 并确保它正确完成。

-dealloc 和 -viewDidUnload 之间的区别在于,您仍在使用 -viewDidUnload 中的完整、功能齐全的对象,而该对象可能已经在 -dealloc 中被部分释放。

【讨论】:

这是否意味着使用accessor和release而不是设置为nil可能会导致dealloc出现不可预知的情况? 我所期望的最糟糕的情况可能是泄漏,但即使这样也会令人惊讶。尽管如此,它还是不太好……您假设有关访问器的实现,它正在返回 ivar 而没有做任何其他事情。通常是正确的,但指望这会破坏封装,这就是我们首先使用属性的原因。 这是否意味着对于每个属性我都需要一个 ivar?恕我直言,同时拥有 ivar 和属性是代码的重复,只是为了我不理解的东西。 如果您正在合成您的属性访问器但没有声明相应的 ivars,那么编译器也在为您合成 ivar。您应该能够更改您的 -dealloc 以直接访问 ivar:[myProperty release]; 应该适合您,即使没有明确将 myProperty 声明为 ivar。【参考方案2】:

我的previous answer 讨论了 Apple 推荐的内容和原因。为了清楚起见,此处转载了相关部分:

另外,来自Apple docs 上的-viewDidUnload

放弃任何对象(包括插座中的对象)所有权的首选方法是使用相应的访问器方法将对象的值设置为 nil。但是,如果您没有给定对象的访问器方法,则可能必须显式释放该对象

那么,就这样吧。如果您的插座有一个与之关联的属性(它们都应该不再),那么在-viewDidUnload 中将其归零——但不要释放它。当您考虑合成访问器中实际发生的事情时,这是有道理的。代码如下所示:

- (void) setMyView1 : (UIView *) view 
   if (myView1) // the associated IVAR is already set
      [myView1 release];

   myView1 = [view retain];

如您所见,将 synthesize 属性设置为 nil 会隐式释放保留的对象。

也来自关于-dealloc的文档:

如果你实现了这个方法,但正在为 ios 2.x 构建你的应用程序,你的 dealloc 方法应该释放每个对象,但还应该在调用 super 之前将该对象的引用设置为 nil。

除非你支持iOS2.x,否则不需要在dealloc中将对象设置为nil。

所以,总结一下 Apple 关于 -viewDidUnload-dealloc 的文档:

-viewDidUnload 中,nil 属性(包括 IBOutlet 属性),但不要释放它们 在 -dealloc 发布属性中,但不要将它们归零(除非为 2.x 构建)。

【讨论】:

以上是关于释放属性的简单模式的主要内容,如果未能解决你的问题,请参考以下文章

c# topmost模式窗口关闭后,有“无法访问已释放的对象”错误

我应该在重新分配之前调用分配给保留属性的自动释放对象的释放吗?

我是不是必须“释放”我声明为具有属性属性“保留”和“非原子”的 IBOutlets 的 UI 对象?

将自动释放的对象分配给保留的属性

我应该在 dealloc 中释放实例变量和属性吗?

从 JSON 设置后立即释放模型属性