是否允许调用 [self release] 来控制对象生命周期?

Posted

技术标签:

【中文标题】是否允许调用 [self release] 来控制对象生命周期?【英文标题】:Is calling [self release] allowed to control object lifetime? 【发布时间】:2009-09-06 11:23:17 【问题描述】:

我想在 Objective C 中创建一个对象,但我没有对它的引用。

是否允许通过调用[self release]让对象控制自己的生命周期?

如果您想知道我为什么需要这个:我想创建一个订阅某些通知的对象,但过了一段时间该对象不再需要并且应该消失了。

那么,以下是否允许?

- (void) destroyMyself 
   [[NSNotificationCenter defaultCenter] removeObserver:self];

   [self release];
 

【问题讨论】:

我从未使用过 Cocoa,但从我在网络版本上随机阅读的内容中,我只是减少了运行时垃圾收集器用来知道何时收集对象的内部计数器,所以这可能是允许的,即使如果它看起来很奇怪。同样,我可能完全错了,因为这只是我从前段时间阅读的内容中做出的假设。 在引用计数环境中,没有垃圾收集器,所以当引用计数为零时,对象会立即被释放。 (在调用 [self release] 之​​后,对象实际上已经消失并被释放) 完全有效。这是“无效模式”的开始。您可能还应该做的是在-init 中将一些实例变量设置为YES,在-destroyMyself 中设置为NO。这样,您可以在其他方法中断言该标志为 YES;如果否,您知道您的对象在您明确打算不再有效之后被使用。 另一个你可能想用它的例子是一个对象,它包含一个 NSTimer 的实例和一个随机的无符号整数(你希望定时器触发的次数)。如果没有其他对象可以知道这个随机整数并声明这个包装的计时器,那么计时器对象可以使其计时器无效然后释放自己? 【参考方案1】:

如果您在代码中看到这一点,它可能是错误的。然而,在某些情况下,有合理的回应可以说是可以辩护的。 (所以请确保您这样做是出于正确的原因。)

当你创建一个对象来下载一个 url 时,这是一个很好的例子。该对象在下载 url 时位于内存中,然后向其代理发送一条消息,说明数据已准备好(或无法下载 url)。一旦它的消息被发送出去,它就会因为不再需要而自行销毁。在这种情况下,创建“url 下载器”的代码/函数甚至可能不再在内存中,即,如果它被调用以响应用户选择菜单项或视图控制器中不再出现在屏幕上的操作.

当创建“下载”对象的代码不关心下载是否完成时,这很有用。

【讨论】:

你的代表不能也做[sender release]之类的事情,而不是发件人做[self release]吗? 我曾经这样做过。然后是ARC。这种工作方式不适合 ARC。 其实有一种方法可以做到,ARC 不抱怨。【参考方案2】:

规则很简单。如果你拥有它,你应该只释放它。即对象是使用以“new”或“alloc”开头的方法或包含副本的方法获得的。

Cocoa Memory Management Rules

因此,一个对象不得执行 [self release] 或 [self autorelease],除非它之前已执行 [self retain]。

【讨论】:

嗯,除了 Apple 的 Objective-C 编程指南说 init 可以在失败时调用 [self release]:developer.apple.com/library/mac/documentation/cocoa/conceptual/… 是的,但我的回答(如下)遵守此规则。创建对象的代码也可以立即释放它,同时,想要将自己保存在内存中的对象(即 url 加载器)可以保留自己,然后再释放自己,从而不违反此规则。【参考方案3】:

引用伟大的哲学家艾丽西亚·西尔弗斯通的话,“I had an overwhelming sense of ickiness”当我读到那句话时。但我真的不能告诉你为什么。

我想我会使用autorelease 而不是简单的release,因为当您调用它时,您仍在执行self 中的代码,但除此之外,我想不出任何技术原因为什么它不会不行。

【讨论】:

那个,或者:[自我释放];自我=无;【参考方案4】:

这是合法的,但要小心。您希望确定在您释放自己之后,没有其他任何东西会向您发送消息。

在我们拥有 CoreData 之前,我已经为一个错误的方案做过这种事情。

【讨论】:

【参考方案5】:

协议的一部分是,如果你向自己发送释放,那么你应该也发送一次保留,我想 这样做。然后就没有什么可疑的了。我的意思是分配代码必须能够控制你的实例的生命周期;它本身只能延长它的寿命,永远不会让它变短(因为它变短了,那么你会突然给实例的分配所有者留下一个无效的指针)。

【讨论】:

你是说我应该在init方法中调用[self retain]? 不,你不应该发送 -retain 给自己,因为在 +alloc 之后你已经有一个非零的保留计数。始终平衡您的保留和释放。如果您发送 +alloc、+new、-copy 或 -retain,请使用 -release 或 -autorelease 平衡它们。 NSResponder:一个实例显然不能实例化自己,所以用户必须向它发送alloc + init;并且必须稍后发送释放或自动释放。所以 +alloc 消息是不让类实现者去平衡 我想让这个类延长它自己的生命,所以我别无选择,只能对自己调用retain。 (因为对象的创建者可以释放对象,根据最佳实践,它应该) 在您描述的情况下,我将遵循 NSTimer 的示例,您的类的用户将使用便捷方法获取实例。 NSTimer 实例在收到 -invalidate 消息时会自行销毁。【参考方案6】:

我将使用 [self autorelease] 而不是 [self release]。因为通常在

中调用
- (void)aMethod

    [self.delegate aDelegateMethod:self];
    [self release];

//If you add code related to self here, after [self release], you are making a huge mistake.

如果我使用 [self autorelease],我仍然可以在 autorelease 之后做一些事情。

【讨论】:

以上是关于是否允许调用 [self release] 来控制对象生命周期?的主要内容,如果未能解决你的问题,请参考以下文章

信号量 也是同步锁,可用来控制线程的并发数

php中的publicprotectedprivate三种访问控制模式及self和parent的区别(转)

Sentinel访问控制规则

面向对象,元类,控制类,对象的创建

是否可以在不使用继承的情况下在viewDidAppear上调用某些代码

如何使用委托给 self 调用 presentViewController?