我有一个每秒触发一次的NSTimer。
每一秒我都有一个需要更改的NSString。
我之前从未尝试过处理内存管理,因此我不确定我所做的是否正确,但是仪器在“alloc”下说stringByReplacingOccurrencesOfString
的代码行有45MB大约一分钟后“活字节”......
(实时字节数每秒都在不断上升,最终导致应用程序崩溃)。
我认为我的问题出在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 /:
}
答案 0 :(得分:2)
您要为每个对象分配两次内存。当您第二次分配并将其分配给同一个变量时,第一块alloc'd内存将变得无法访问且无法释放。
然后你制作一个testsable的mutableCopy并将副本分配给原始变量。再一次,你留下了一块无法访问的内存。
非ARC内存管理的规则是 - 对于每个 alloc , new , copy 或保留您需要有相应的发布。你有6个分配,一个副本,只有3个版本。
以下是一些建议。
删除这些重复的分配:
testedit = [[NSString alloc] init];
withString1a = [[NSString alloc] init];
forString1a = [[NSString alloc] init];
据推测,testedit
,withString1a
和forString1a
都是iVars。 (Please declare your iVars as autosynthesized properties并将它们称为self.testedit ...等,这将使您的代码更清晰地堆叠溢出程序)。
取出所有这些:
if (testedit) {
[testedit release];
[withString1a release];
[forString1a release];
}
假设这些都是iVars,释放它们的正确位置在对象的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
,访问者和dealloc
方法是不使用属性语法引用iVar的三个地方。)
一切都很好,但实际上,你应该使用ARC!与使用编译器为您管理内存相比,您更容易以这种方式引入内存错误。
答案 1 :(得分: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语句而没有在执行之前释放变量。这会导致它丢失该变量的引用,您将泄漏它。你不需要那么多的分配语句。对于每个分配或保留,应该有相应的发布/自动释放语句。
答案 2 :(得分:0)
您正在收到内存泄漏,因为您从未取消分配testedit
。每当你调用alloc时,这意味着你需要释放它。这通常只意味着调用release
。
执行类似的操作,然后确保释放已分配的内存:
NSString* newString = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy];
答案 3 :(得分:0)
如果您使用ARC,则不应该有问题。如果您不使用ARC,可以尝试添加autorelease
:
testedit = [[[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy] autorelease];