iOS内存管理后续。dealloc和nil有何区别?

3

关于这篇文章: iPhone - dealloc - Release vs. nil

本文主要讨论在Objective-C中释放内存的两种方法:使用release和使用nil。在iOS 5之前,使用release是标准做法,但是在iOS 5及以后版本中,使用nil已经取代了release成为更好的选择。

1) [foo release];
2) self.bar = nil;

以下是解释:
  1. 通过实例变量 bar 访问对象并将其释放。实例变量将变成悬空指针。这是在 dealloc 中的首选方法。

  2. 在 self 上将属性 bar 赋值为 nil,实际上会释放该属性当前所保留的任何内容。如果您有一个自定义 setter 用于清理支持属性的实例变量以外的其他内容,则应执行此操作。

请问有人可以澄清 #1 的解释吗?通过实例变量 bar 访问?

例如,我已在对象头中设置了一个私有变量:

SomeObject *oPointer;

我在头文件中没有使用属性设置器,因此在实例化对象时不会被合成。

在我的代码中,根据特定条件,稍后必须分配并将该指针分配给它的对象。

obj = [[SomeObject alloc] initWith....];

现在可以通过实例变量obj进行访问。我有一个UIButton,它被配置为重置这个对象,它附加的方法deallocs它。我是通过以下方式完成的:

[obj release];
obj = nil;

在解释了这么多之后,问题是,为什么我还需要声明obj = nil呢?似乎[obj release]调用也会使指针失效。我认为[obj release]会在一次操作中释放它所指向的内存并将obj设置为nil,但事实并非如此,因为在[obj release]之后尝试引用obj时我的应用程序会崩溃。
这个问题有意义吗?解释是否只是[obj release]执行所有清理操作,包括杀死指针,我需要注意这一点?
如果我为SomeObject指针设置保留属性,释放后指针是否仍然被保留?
提前感谢您的帮助!
4个回答

4

使用nil的原因有两个:

  • nil是安全的,可以调用方法,而已经被释放的引用则不能。

如果是一个retain属性,self.thinger = nil;也会调用release。如果不是,则不会。

  • 你想要保持DRY的代码,无论你使用assign/retain标签,都不想改变任何东西。在deallocs中使用release必须与属性保持同步。

如果你严格使用autorelease,除了对于retain属性的自定义setter之外,几乎永远不需要自己调用release

请查看关于NARC的开创性文章。autorelease是你的朋友。


3

调用release将减少obj的引用计数。如果引用计数变为0,则会被释放。指针obj仍然指向相同的内存位置,但访问它可能会导致程序崩溃。将obj设置为nil并非严格必要的,但它强化了obj不再有效的概念。在调试时或以后重新创建obj并使用“if(obj!= nil)”检查以查看是否已经创建它时,这可能很有用。

如果将其设置为属性的保留,则在调用“self.obj = someObj”时,Objective C将使someObj的引用计数加1。不应该自己调用retain,在通过alloc-init创建的内容上,因为alloc-init已经将引用计数设置为1。如果保留该对象,则在释放它时,引用计数只会回到1,它将成为内存泄漏。


3

[obj release]; 此方法会将指向对象 obj 的保留计数减 1,并有可能导致其被释放。但是,这不会改变 obj 指针,它仍然指向内存中的某个位置。

obj = nil; 该语句会将 obj 指针设置为 nil,虽然这并非必需,但推荐使用。如果你没有进行此操作,但仍继续使用 obj 指针,则很可能会意外访问以前保存已释放对象的内存位置。如果该对象已被释放,这将导致崩溃或者其他未预期的行为。通过将 obj 设置为 nil,确保将来对其进行的任何使用将发送消息到 nil,并具有正常定义行为。


0
释放对象仍然指向同一个对象。我总是在viewDidLoad和applicationDidFinishLaunching两个方法中都这样做。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接