【问题标题】:Proper memory management when appending to NSString附加到 NSString 时的正确内存管理
【发布时间】:2011-11-14 23:45:57
【问题描述】:

我已经分配了一个NSString 对象。我想在应用程序的整个生命周期中偶尔附加到这个字符串 我对如何在下面的示例中正确处理内存感到困惑。谢谢。

  1. 我是否需要保留每次添加的字符串,还是可以添加属于自动释放池的字符串,如stringByAppendingString: 返回的那样?
  2. 每次执行追加操作时,我是否都会泄漏先前分配给 my_string 的内存?

代码:

NSString* my_string = [[NSString alloc] initWithString:@"Initial string"];
NSString* something = [NSString stringWithFormat:@"%@", @" with something"];
my_string = [[my_string stringByAppendingString:something] retain];
NSString* something_else = [NSString stringWithFormat:@"%@", @" and something_else"];
my_string = [[my_string stringByAppendingString:something_else] retain];
[my_string release];

【问题讨论】:

  • 仍在自己管理内存!为什么不在 Xcode 4.2 中使用 ARC!!

标签: ios memory nsstring


【解决方案1】:
NSString* my_string = [[NSString alloc] initWithString:@"Initial string"];

不是自动释放的(因为它是使用 init... 方法创建的,这是一个约定),它的 retainCount 为 1。

NSString* something = [NSString stringWithFormat:@"%@", @" with something"];

自动释放。

是否可以附加一个属于自动释放池的字符串,如 stringByAppendingString:返回

只要您期望它能够生存就可以。但是在您的代码中:

NSString* my_string = [[NSString alloc] initWithString:@"Initial string"];
NSString* something = [NSString stringWithFormat:@"%@", @" with something"];
my_string = [[my_string stringByAppendingString:something] retain];

你有泄漏。您应该在重新分配之前自动释放 my_string。所以最后一行应该是:

my_string = [[[my_string autorelease] stringByAppendingString:something] retain];

否则,您将永远丢失指向您要释放的对象的指针。当您保留结果时,您有责任释放它,因此您在最后一行之前也有泄漏,应该是

my_string = [[[my_string autorelease] stringByAppendingString:something_else] retain];

【讨论】:

  • 谢谢,这是有道理的,我每次执行附加操作时首先需要自动释放 my_string。这看起来真的很难看。没有更好的方法来简单地附加到现有字符串而不首先释放旧字符串并保留创建的新字符串吗?再次感谢。
  • NSMutableString?问题是NSString 是不可变的,它只返回全新的对象,然后当您将它们分配给同一个变量时,这些对象会覆盖对旧不可变对象的引用,从而导致泄漏。 NSMutableString 可以让你附加到字符串,不需要额外的分配。
  • 谢谢杰蒙斯。非常感谢。
  • 你也可以不保留它们,那么你就不必自动释放它们:)
【解决方案2】:

首先要记住的是NSString 是不可变的。无论您是分配、使用格式创建还是追加,您总是会返回一个 new 字符串对象。所以让我们分解一下:

NSString* my_string = [[NSString alloc] initWithString:@"Initial string"];
//String object created with "Initial string" content. Retain +1

NSString* something = [NSString stringWithFormat:@"%@", @" with something"];
//String object created with content " with something" and autoreleased.

my_string = [[my_string stringByAppendingString:something] retain];
//String object created with content "Initial string with something", autorelesed, and retained. Effective retain +1
//Assignment replaces old "Initial string" reference. "Initial string" object still has retain of +1, so it doesn't get deallocated (it leaks).

NSString* something_else = [NSString stringWithFormat:@"%@", @" and something_else"];
//String object created with content " and something_else" and autoreleased.

my_string = [[my_string stringByAppendingString:something_else] retain];
//String object created with contents "Initial string with something and something_else", autoreleaased, and retained. Effective retain +1
//Assignment replaces old "Initial string with something" reference. "initial string with something" object still had a retain of +1, so the object leaks.

[my_string release];
//String object "Initial string with something and something_else" released. Retain -1. Object is deallocated and doesn't leak.

//...Sometime later at the end of the runloop, the autorelease pool is drained and " with something" and " with something_else" are both deallocated.

所以:

  1. 是的。可以附加一个自动释放的字符串。 release 在运行循环结束之前不会在自动释放的对象上调用,至少是在此方法退出之后。

  2. 是的,每次执行追加操作时,您都会泄漏先前分配给 my_string 的对象...但导致泄漏的不是追加,而是分配。您可以将nil 分配给my_string,如果您没有先使用releaseautorelease,则用于指向的保留对象my_string 仍然会泄漏。

【讨论】:

  • 谢谢,您同意 jbat100 的观点,即这是附加到现有字符串的最佳方式:my_string = [[[my_string autorelease] stringByAppendingString:something] retain];
  • 我上面的评论假定 my_string 必须在当前运行循环结束后仍然有效。初始字符串分配不会发生在同一个代码块中。在这种情况下,您同意上述评论吗?谢谢。
  • 如果my_string 必须在运行循环结束之后(并且在给定方法之外)有效,那么属性可能是正确的解决方案?综合属性为您处理所有释放和保留。或者NSMutableString?出于习惯,我可能会 NSString *oldString = my_string; my_string = [[my_string stringByAppendingString:@"foo"] retain]; [oldString release]; 以免等待自动释放旧字符串的 RAM 被回收(在早期的 iPhone 型号上很重要)。但无论哪种方式都可以。
  • 在第一行代码之后保留计数不会是 1.... 但这是一个实现细节。底线;将保留计数视为绝对值是错误的。
  • @bbum 谢谢!非常真实。在回答这样的问题时,是否有一种很好的方式来表达“您有 X 个不透明的所有权单位投资于该对象,必须与 X 个 releaseautorelease 调用相平衡”而不暗示与 @987654335 的(错误)关系@?除了“使用 ARC”,我的意思是 ;-)
【解决方案3】:

在第二个作业中,您丢失了第一个 stringByAppendingString 调用的保留引用,所以:

  1. 可以在不调用保留的情况下附加字符串,除非您稍后在代码中需要该值。
  2. 是的,每次调用stringByAppendingString 都会返回一个新的自动释放字符串。如果您暂时使用该值,请不要保留它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-12
    • 1970-01-01
    相关资源
    最近更新 更多