0

我有一个每秒触发一次的 NSTimer。

每一秒我都有一个需要更改的 NSString 。

我以前从未尝试过处理内存管理,所以我不确定我所做的是否正确,但仪器在“alloc”下说stringByReplacingOccurrencesOfString大约一分钟后代码行有 45MB 的“Live Bytes” ...

(并且实时字节数每秒都在增加,最终导致应用程序崩溃)。

我认为我的问题在于MutableCopy代码的某个地方?

这是我的代码:

-(void)myTimer {
    if (testedit) {
        [testedit release];
        [withString1a release];
        [forString1a release];
    }
    testedit = [[NSString alloc] init];
    withString1a = [[NSString alloc] init];
    forString1a = [[NSString alloc] init];

    testedit = [[NSString alloc] initWithFormat:@"example"];
    withString1a = [[NSString alloc] initWithFormat:@"e"];//this string gets its values randomly from an array in my real code
    forString1a = [[NSString alloc] initWithFormat:@"flk34j"];//this string gets its values randomly from an array in my real code

    testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a]  mutableCopy];//memory leak /:

}
4

4 回答 4

2

您为每个对象分配了两次内存。当您第二次分配并将其分配给同一个变量时,分配的第一块内存变得不可访问且不可释放。

然后你制作一个 testit 的 mutableCopy 并将副本分配给原始变量。再一次,你留下了一块无法访问的内存。

非 ARC 内存管理的规则是 - 对于每个allocnewcopyretain,您需要有一个相应的release。你有 6 个分配器,一个副本,只有 3 个版本。

这里有一些建议。

删除这些重复的分配:

   testedit = [[NSString alloc] init];
   withString1a = [[NSString alloc] init];
   forString1a = [[NSString alloc] init];

大概testeditwithString1a并且forString1a都是 iVar。(请将您的 iVar 声明为自动合成的属性,并将它们称为 self.testedit ... 等,这将使您的代码对堆栈溢出器更加清晰)。

取出所有这些:

if (testedit) {
        [testedit release];
        [withString1a release];
        [forString1a release];
    }

假设这些都是 iVar,释放它们的正确位置是在对象的dealloc方法中

实际上withString1a,并且forString1a可以是局部变量,因为您从其他地方获取它们的内容:

 NSString*  withString1a = [[[NSString alloc] initWithFormat:@"e"] autorelease];
 NSString*  forString1a =  [[[NSString alloc] initWithFormat:@"flk34j"] autorelease];

您可以autorelease使用它们,因为在方法完成后您不需要它们闲逛。

这些行也可以写成:

 NSString*  withString1a = [NSString stringWithFormat:@"e"];
 NSString*  forString1a =  [NSString stringWithFormat:@"flk34j"];

(-stringWithFormat 是一种返回自动释放对象的便捷方法)

这给我们留下了这两行。

  testedit = [[NSString alloc] initWithFormat:@"example"];
  testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a 
                                                  withString:forString1a]  mutableCopy];

目前尚不清楚为什么您将 testit 视为第一行中的不可变字符串和第二行中的可变字符串。您根本不需要可变字符串,因为您要替换testedit为新字符串。

 self.testedit = [[NSString alloc] initWithFormat:@"example"];
 self.testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a 
                                                  withString:forString1a] copy]; 

(你需要copy作为stringByReplacingOccurrencesOfString:withString:返回一个自动释放的对象,在这里你想保留它)

拼图的最后一块是摆脱您的 _testedit iVar 内存分配。您可以在dealloc对象的方法中执行此操作:

- (void) dealloc {
    [_testEdit release];
    [super dealloc];
}

(请注意init,访问器和方法是不应使用属性语法引用 iVardealloc的三个地方。)

一切都很好,但实际上,您应该使用 ARC!与依靠编译器为您管理内存相比,您更有可能以这种方式引入内存错误。

于 2013-01-22T22:37:07.693 回答
1

我建议你利用@property这里。

在 .h 文件中将属性声明为:

@property (nonatomic, retain) NSString *testedit;
@property (nonatomic, retain) NSString *withString1a;
@property (nonatomic, retain) NSString *forString1a; //if required write the @synthesize as well in .m class

您可以将计时器方法编写为:

-(void)myTimer {

    self.testedit = @"example";
    self.withString1a = @"e";//this string gets its values randomly from an array in my real code
    self.forString1a = @"flk34j";//this string gets its values randomly from an array in my real code
    self.testedit = [self.testedit stringByReplacingOccurrencesOfString:self.withString1a withString:self.forString1a];
}

在 dealloc 方法中,您可以将上述所有属性设置为nil( self.testedit = nil;) 或对其进行释放 ( [testedit release];)。

如果可能,尝试切换到 ARC,您不必担心内存管理。您的代码的问题是您使用了很多 alloc/init 语句而没有在执行之前释放变量。这会导致它丢失该变量的引用,并且您将泄漏它。您不需要那么多分配语句。对于每个分配或保留,都应该有相应的释放/自动释放语句。

于 2013-01-22T23:01:51.890 回答
0

你得到了内存泄漏,因为你从来没有 de-allocate testedit。每当您调用 alloc 时,这意味着您需要释放它。这通常意味着调用release.

改为这样做,然后确保释放您分配的内存:

NSString* newString = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a]  mutableCopy];
于 2013-01-22T22:38:00.037 回答
0

如果您使用的是 ARC,则应该没有问题。如果您不使用 ARC,您可以尝试添加autorelease

testedit = [[[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a]  mutableCopy] autorelease];
于 2013-01-22T22:44:35.233 回答