11

在一本书中,是这样说的:

那么你怎么知道一个对象什么时候拥有,由谁拥有呢?考虑以下示例:

NSString *str = [[NSString alloc] initWithString:@”Hello”];  
NSString *str2 = str;

在此示例中,您使用alloc关键字 for str,因此您拥有str。因此,您需要在不再需要它时释放它。但是, str2只是指向str,因此您不拥有str2,这意味着您使用完后无需释放str2它。

我认为所有权是对象,而不是变量或指针......所以我们不能说我们“拥有str”或“拥有”......我们拥有一个由orstr2指向的对象,如果我们使用or ,都是一样的。strstr2[str release][str2 release]

另一种描述是:

例如,考虑上一节中使用的示例:

NSString *str = [[NSString alloc] initWithString:@”Hello”]; 
NSString *str2 = str;
[str release];
[str2 release]; //---this is not OK as you do not own str2---

尝试释放str2将导致运行时错误,因为您无法释放不属于您的对象。

[str2 release]如果之前调用了它,我们实际上可以使用 它[str release]。如果我们这样做,那么该行将[str release]导致错误,因为 nowstrstr2都是悬空指针,并且假设release第一次发送到对象时,引用计数变为 0,并dealloc立即被调用,并且内存被释放由 C 函数free()

以上是否正确,或者还有其他需要更正的地方?

4

5 回答 5

5

不要从管理内存的角度考虑它,而是从对象所有权的角度考虑。当您分配、保留或复制对象时,您将获得对象的所有权。您负责完全释放您拥有的对象,而不是其他对象。

在您的示例中,分配 tostr2不获取对象的所有权,但是如果您确实需要对它的第二个“拥有”引用,那么您应该这样做[str2 retain],之后这样做不是错误[str release]; [str2 release];。这也是使用 ARC 会自动发生的情况,除非您将其注释str2为弱引用。(当然,在这种简单的情况下,编译器可以在内部优化不必要的保留/释放。)

于 2012-05-13T13:33:58.173 回答
3

你的猜测是正确的:这本书使用模糊语言(即使含义是正确的)来简化指针:

您拥有该对象strstr2指向该对象。

这当然意味着您只能释放对象一次(或者更确切地说,它被保留的频率是一次 - 在您的示例中,隐含地, by alloc),并且您是否通过strstr2(或任何其他方式)这样做是无关紧要的。

但是,在实践中,您应该将变量视为您拥有它们。这使得跟踪保留/释放对变得更加容易,并且您不能依赖这样一个事实,即没有人在两者之间的某个地方更改这些变量之一的值。

将指向已释放实例的所有变量设置为nil之后是一种很好的做法(但不是必需的)。

深入研究技术细节(实际上应该将其视为:实现细节;私有 API 的工件):

从技术上讲,没有人拥有该对象。该对象有一个它被保留的次数的计数器(你可以通过调用来找到它anObject retainCount- 但你不应该,尤其是因为有些对象有一个虚假的retainCount,而且因为它真的与你无关)。当一个对象被alloced时,它的retainCount为1。每发送一次retain(“它被保留”),它的retainCount就加1,每发送一次release(“它被释放”),它的retainCount就减1 1.

一旦对象的 retainCount 达到零,它就会被释放(并dealloc调用它的方法)。

谁发送了所有这些retain/release消息(以及通过哪些变量)并不重要。

再说一遍:这些是实现细节。它们是 Objective-C/Cocoa 进行内存管理的方式的产物。像对待任何私有 API 一样对待它们:很好奇,但永远不要依赖内部。仅在生产代码中使用公共 API(在本例中为retain/release和自动释放池)。

注意:一些对象(例如一些单例)会覆盖默认的保留/释放方法。永远不要相信retainCount你从一个对象中得到的东西,除非是出于好奇(例如看看 retainCount [UIColor clearColor])。

有关此主题的更多想法,此问题及其答案可能是一个很好的总结/起点。

也就是说,考虑切换到 ARC,这将使您摆脱几乎所有内存管理的麻烦。

于 2012-05-13T13:10:50.003 回答
2

我认为所有权是对象,而不是变量或指针......所以我们不能说我们“拥有str”或“拥有str2”......我们拥有一个由str或str2指向的对象,如果我们使用 [str release] 或 [str2 release],都是一样的。

这是对的。

我认为作者所说的“我们拥有 str”的意思是您拥有该字符串实例。不是指针或变量。理论上,您可以使用其他指针释放对象。但通常最好使用用于初始化对象的变量来释放。

于 2012-05-13T13:09:39.343 回答
1

我认为其他答案是错误的或不完整的。

所有权由谁释放资源来定义。一个对象(通常)不拥有自己,它是拥有的。

同样:所有者是负责释放内存的人。

在你的代码中,str已经声明了它对对象的所有权,str2还没有。为了str2也拥有该对象(共享 str所有权),您需要retain它:

[str2 retain];

现在你可以稍后说,

[str2 release];

放弃str2对所有权的要求,对于str.

另一方面,对于 ARC,指向资源的所有(引用计数)指针都是它的共享所有者。在这种情况下,所有指针都负责跟踪对象引用计数,并在确定它们是唯一所有者并超出范围时释放对象。

重申:所有权不是按客体的。所有权是指向对象的指针,以及这些指针的所有者,但前提这些指针可能在某些情况下被释放。如果不存在释放资源的情况,则指针是非拥有的。在这种情况下,它们被称为

如果对象拥有自己,弱指针的概念将毫无意义(因为所有指针都是弱指针)。

于 2012-05-13T18:54:29.580 回答
0

如果释放strstr2,则释放内存位置strstr2指向 。所以,你只需要调用stror str2,而不是两者,因为它们指向同一个内存位置。

我不明白“拥有”一个变量是什么意思,据我所知,指针可以指向内存中的一块空间,仅此而已。

于 2012-05-13T13:07:20.667 回答