内存泄漏NSString

时间:2011-07-06 23:23:36

标签: objective-c memory-management ios4 nsstring

我在这里几乎阅读了关于涉及NSStrings的内存管理的所有问题,但我无法真正解决这个问题。

@interface:

@property (nonatomic, retain) NSString *criticalTranscription;

@implementation: viewDidLoad中:

criticalTranscription = [[NSString alloc] init];

NSArray *paragraphs = [doc valueForKeyPath:@"critical.text"];
for(int i = 0; i < [paragraphs count]; i++) 
{
    criticalTranscription = [criticalTranscription stringByAppendingString:[[paragraphs objectAtIndex:i] valueForKey:@"p"]];
    criticalTranscription = [criticalTranscription stringByAppendingString:@"\n\n"];
}
[transcription setText:criticalTranscription];

@XIB 带有IBAction的UISegmentedControl链接到:

- (IBAction) changeText:(id)sender
{
  if(transcriptionSelector.selectedSegmentIndex == 1)
    [transcription setText:diplomaticTranscription];
  else
    [transcription setText:criticalTranscription];
}

当我更改UISegmentControl的值(加载后第一件事,没有其他运行),我遇到这个错误(NSZombieEnabled = YES):

2011-07-07 01:10:43.639 Transcribe[404:707] *** -[CFString length]: message sent to deallocated instance 0x1189300

我无法在回溯中看到任何相关内容。没有NSZombieEnabled,criticalTranscription只指向随机数组或其他东西。没有进一步使用变量或任何版本。

我在没有任何可疑泄漏的情况下运行分析。

有什么问题?

3 个答案:

答案 0 :(得分:3)

问题是你要用你不拥有的字符串覆盖对你拥有的字符串的引用。

// you own the empty string returned here
criticalTranscription = [[NSString alloc] init]; 

NSArray *paragraphs = [doc valueForKeyPath:@"critical.text"];
for(int i = 0; i < [paragraphs count]; i++) 
{
    // immediately overwrite allocated instance (that you own)
    criticalTranscription = [criticalTranscription stringByAppendingString:[[paragraphs objectAtIndex:i] valueForKey:@"p"]];
    criticalTranscription = [criticalTranscription stringByAppendingString:@"\n\n"];
}

但是,请勿使用此方法,因为它会使用不必要的字符串污染自动释放池。相反,使用可变字符串并将字符串附加到单个可变字符串实例。

此外,为了利用该属性的内置内存管理,您需要使用self.criticalTranscription而不仅仅是criticalTranscription。如果没有self.,则直接使用实例变量。

答案 1 :(得分:1)

在你的for循环中

criticalTranscription = [criticalTranscription stringByAppendingString:[[paragraphs objectAtIndex:i] valueForKey:@"p"]];
criticalTranscription = [criticalTranscription stringByAppendingString:@"\n\n"];

您正在将criticalTranscription设置为自动释放的字符串对象但不保留它,从而导致火焰死亡。

您可以保留它或使用@property(nonatomic, copy)NSString *criticalTranscription;的属性并使用该属性而不是ivar。

答案 2 :(得分:1)

两个问题:

  • 您正在泄漏字符串的第一个实例
  • 您分配给它的每个后续值都是自动释放的

要解决此问题,最简单的方法是将criticalTranscription更改为NSMutableString。然后你可以这样做:

criticalTranscription = [[NSMutableString alloc] init];

NSArray *paragraphs = [doc valueForKeyPath:@"critical.text"];
for(int i = 0; i < [paragraphs count]; i++) 
{
    [criticalTranscription appendString:[[paragraphs objectAtIndex:i] valueForKey:@"p"]];
    [criticalTranscription appendString:@"\n\n"];
}
[transcription setText:criticalTranscription];

......或者,

[criticalTranscription appendFormat:@"%@\n\n", [[paragraphs objectAtIndex:i] valueForKey:@"p"]];

另请注意,您需要在release完成criticalTranscription之后,-viewDidLoad或其相应的-viewDidUnload