【问题标题】:Objective C Memory Management WoesObjective C 内存管理问题
【发布时间】:2011-03-13 21:32:32
【问题描述】:

我知道这已经被讨论过了,但我只是没有得到一些内存管理。我知道保留使对象保持活动状态,而副本则为对象提供了单独的副本。

当谈到 ivars 和属性时,我不明白的是,作为属性保留意味着 setter 释放旧值并保留新值:

property = newValue;
// retain
if (property != newValue)
{
   [property release];
    property = [newValue retain];
}

但我已经看到了将静态字符串分配给保留属性 ivars 的示例,例如

self.stringProperty = @"something";
(some other code)
self.stringProperty = @"somethingElse";

第二次调用set string应该对静态字符串调用release,这是不允许的,为什么程序不会崩溃?

另外,如果一个对象是用retain属性声明的,然后用init分配一些东西,例如

@property(retain)someArray;

someArray = [[NSArray alloc] initWithArray:arbArray];

这是否意味着 someArray 现在的保留计数为 2 但如果它是用创建的

someArray = [NSArray arrayWithArray:arbArray];

因为第二个是工厂方法,所以保留计数只有 1?

【问题讨论】:

  • 对不起,我的意思是两个样本中的 self.someArray。

标签: objective-c memory-management nsstring nsarray nsobject


【解决方案1】:

第二次调用set string应该对静态字符串调用release,这是不允许的,为什么程序不会崩溃?

它不是一个静态字符串,它是一个常量字符串。但是,这与问题无关,但实际上您可以将 -retain 发送到从 NSObject except NSAutoreleasePool 派生的任何 Objective-C 对象。如果你看一下常量 NSString 的 retainCount(有点调皮,但是因为我们正在讨论实现,好吧),例如

NSLog(@"retain count = %u", [@"foo" retainCount]);

您很可能会发现它被设置为一个非常大的数字(实际上是 UINT_MAX)。这是运行时忽略释放和保留调用的信号。

顺便说一句,忘记释放对象不会立即使程序崩溃。事实上,如果您有大量 RAM,您可能在操作系统开始交换之前不会注意到。

这是否意味着 someArray 现在的保留计数为 2 但如果它是用创建的

不,因为您没有使用属性来分配新数组,所以您直接进入了 ivar:

self.someArray = [[NSArray alloc] initWithArray:arbArray];

会泄漏。

self.someArray = [NSArray arrayWithArray:arbArray];

会好的。

【讨论】:

    【解决方案2】:

    这不仅仅是一个问题,但无论如何......

    静态字符串在很多方面都是特殊情况,其中之一是您可以 retainrelease 随心所欲地使用它们而不会产生任何影响。

    顺便说一句,NString 属性通常具有copy 而不是retain 语义,如果重要的话,无论如何都会避免这个问题。但事实并非如此。

    在您的第二种情况下,直接从alloc(或copy 或其他授予所有权的调用)分配给retain 属性是不好的做法,除非您事后主动添加相应的release,否则会泄漏,或autorelease 期间,例如:

    self.someArray = [[[NSArray alloc] initWithArray:arbArray] autorelease];
    

    但在这种特殊情况下,确实没有理由不使用类方法。

    【讨论】:

    • 关于保留计数的第二部分是我的实际问题,第一部分只是困扰我的事情,但我将来会分开问题。感谢您的回复。
    【解决方案3】:

    第二次调用set string应该对静态字符串调用release,这是不允许的,为什么程序不会崩溃?

    您可以将release 传递给一个常量字符串,它不会做任何有意义的事情,因此这些代码行是有效的。

    这是否意味着 someArray 现在的保留计数为 2,但如果它是用...创建的,则保留计数仅为 1,因为第二个是工厂方法?

    首先,

    someArray = [[NSArray alloc] initWithArray:arbArray];
    

    不使用@property创建的方法,它只是直接访问ivar。要使用属性方法,您必须使用self.someArray = ...;

    是的,

    [[NSArray alloc] initWithArray:arbArray]
    

    返回一个有效保留计数为 1 的对象,并且

    [NSArray arrayWithArray:arbArray]
    

    返回一个有效保留计数为 0 的对象,因此如果您确实将它们传递给由 @property 创建的“保留”设置器,则 ivar 的有效保留计数将为 2 并且1,分别。

    【讨论】:

    • 谢谢。我不记得良好沟通的所有 5 个 C,但您的回答满足了我记得的 3 个:清晰、简洁、正确。
    猜你喜欢
    • 2011-05-11
    • 1970-01-01
    • 1970-01-01
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 2015-01-29
    • 1970-01-01
    相关资源
    最近更新 更多