我可以使用 [self retain] 在objective-c 中保存对象本身吗?
Posted
技术标签:
【中文标题】我可以使用 [self retain] 在objective-c 中保存对象本身吗?【英文标题】:Can I use [self retain] to hold the object itself in objective-c? 【发布时间】:2011-03-23 02:57:40 【问题描述】:我使用 [self retain] 来保存对象本身,并使用 [self release] 在其他地方释放它。这有时非常方便。但这实际上是一个引用循环或死锁,大多数垃圾收集系统都希望解决这个问题。我想知道objective-c 的自动释放池是否可以找到循环并通过在达到[自我释放] 之前释放对象来给我惊喜。我的方式是否受到鼓励?我如何确保垃圾收集(如果有)不会太聪明?
【问题讨论】:
你可能想要避免这种模式,除了一些非常特殊的情况。你能告诉我们更多关于你的使用背景吗?当必须从其他地方进行分配时,为什么对象会自我保留? 上下文是,我使用 UIViewController 的子类作为全屏模型对话框。父视图发出对话框,但是当对话框关闭时,它确实需要知道事件。 上下文是,我使用 UIViewController 的子类作为全屏模型对话框。父视图发出对话框,但是当对话框关闭时,它确实需要知道事件。如果我直接使用 UIView 而不是 UIViewController,就没有这样的问题,因为当 [self removeFromSupperView] 时,视图的引用计数减少了一个。但是,UIViewController 的子类可以自动链接到同名的 xib 文件,这就是我使用 UIViewController 的原因。 【参考方案1】:这种工作方式非常不受欢迎。看起来你需要一些关于内存管理的指针。
理论上,一个对象只要有用就应该存在。有用的对象很容易被发现:它们被直接引用到线程堆栈的某个地方,或者,如果您制作了所有对象的图表,则可以通过链接到线程堆栈某处引用的对象的某个路径访问它们。没有被引用的“自己”存在的对象没有用处,因为没有线程可以访问它们以使它们执行某些操作。
这就是垃圾收集器的工作方式:它遍历您的对象图并收集每个未引用的对象。请注意,Objective-C 并不总是垃圾收集,因此必须建立一些规则。这些是memory management guidelines for Cocoa。
简而言之,它基于“所有权”的概念。当您查看一个对象的引用计数时,您会立即知道有多少其他对象依赖于它。如果一个对象的引用计数为 3,则意味着其他三个对象需要它才能正常工作(因此拥有它)。每次你保留一个对象的引用(除了在极少数情况下),你应该调用它的retain
方法。在你删除引用之前,你应该调用它的release
方法。
关于对象的创建还有一些其他重要的规则。当您调用alloc
、copy
或mutableCopy
时,您获得的对象的引用计数已经为1。在这种情况下,这意味着调用代码负责释放不需要的对象。当你返回对对象的引用时,这可能会出现问题:一旦你返回它,理论上你就不再需要它了,但是如果你在它上面调用release
,它就会立即被销毁!这就是 NSAutoreleasePool
对象的来源。通过在对象上调用 autorelease
,您放弃它的所有权(就像您调用 release
),除了引用不会立即撤销: 相反,它被转移到NSAutoreleasePool
,一旦它收到release
消息本身就会释放它。 (每当您的一些代码被 Cocoa 框架回调时,您可以确信自动释放池已经存在。)
这也意味着如果您没有调用alloc
、copy
或mutableCopy
,则您不拥有对象;换句话说,如果您以其他方式获得对此类对象的引用,则无需在其上调用release
。如果您需要保留这样的对象,像往常一样,在它上面调用retain
,然后在完成后调用release
。
现在,如果我们尝试将此逻辑应用到您的用例中,它会显得很奇怪。一个对象不能在逻辑上拥有自己,因为这意味着它可以独立存在于内存中,而不会被线程引用。显然,如果你有机会自己调用release
,这意味着你的方法之一正在执行;因此,你必须有一个参考,所以你首先不需要retain
自己。对于您提供的一些细节,我真的不能说,但您可能需要查看 NSAutoreleasePool
对象。
【讨论】:
感谢您提供详细信息。我已经在 C++ 中完成了一些垃圾收集工作,所以我知道它是如何工作的基础知识,比如维护依赖关系和通过从堆栈或全局对象开始查找引用闭包。这就是为什么我想知道objective-c是否会这样做。我没有在问题中给出上下文,所以我在这里添加它:我正在使用 UIViewController 的子类作为对话框。当一个对话框关闭时,它只是调用 [self.view removeFromSuperView] 并且在大多数情况下不需要通知它的所有者。 UIViewController 必须想办法释放自己。如果objective-c是很好的垃圾回收 ...如果objective-c被很好的垃圾回收,self.view也应该维护一个对self(UIViewController)的引用,并且在调用[self.view removeFromSuperView]之前,引用闭包具有外部参考(超级视图),并且不会被释放。但是在调用 [self.view removeFromSuperView] 之后,引用循环(self & self.view)变成了死闭包,因此可以被垃圾回收系统找到并释放。 Objective-c 的垃圾回收似乎是半自动的,并没有以这种方式实现,这让我认为这意味着鼓励自我保留?我知道人们应该始终尽量避免 我知道应该尽量避免这种情况,但是在使用 UIViewController 等遗留代码时,如果我可以这么说,如何平衡便利性和完整性? "很明显,如果你有机会自己调用 release ,这意味着你的方法之一正在执行;因此,你必须有一个参考,所以你不应该需要留住自己。” --- 说的很对!但在我的情况下,引用,即调用 onCloseButton,在 InterfaceBuilder 中链接。我们可以说 UIView 触发了事件,所以 UIViewController 正在等待 UIView 释放它。 UIView 在 UIViewController 的 onCloseButton 中完成工作,所以变成了【自释放】。只是你喜欢哪种形式的问题? @willzeng Whew,cmets 中有很多信息!您可能需要编辑您的问题以进行编辑。【参考方案2】:如果您使用的是保留/释放内存模型,这应该不是问题。没有什么会去寻找你的[self retain]
并颠覆它。但是,如果您切换到使用垃圾收集,则情况可能并非如此,其中 -retain 和 -release 是无操作的。
Here's another thread on SO on the same topic.
我会重申包含“压倒性恶心感”这句话的答案。这并不违法,但除非有非常充分的理由,否则感觉就像一个糟糕的计划。如果没有别的,它似乎是偷偷摸摸的,这在代码中从来都不好。请注意该线程中的警告以使用 -autorelease 而不是 -release。
【讨论】:
以上是关于我可以使用 [self retain] 在objective-c 中保存对象本身吗?的主要内容,如果未能解决你的问题,请参考以下文章
IOS 关键字self,super,copy, retain, assign , readonly , readwrite, nonatomic @synth