如何避免iPhone应用中内存泄露
2013-08-22 13:40:16 来源:WEB开发网name 在调用至 drain 后是未定义的,因为当池被释放时,name 也将被释放。
如果我们用如下的部分替代赋值:
[self setName:[self GetOutput]];
然后 name 将被这个类所有,在使用时保留直到调用 release
那么我们何时释放对象?
由于 name 是成员变量,释放它的最安全的办法是对它所属的类使用 dealloc 函数。
- (void)dealloc
{
[name release];
[super dealloc];
}
注意:虽然并不总是调用 dealloc,依靠 dealloc 来释放对象可能是危险,可能会触发一些想不到的事情。在出口处,iPhone OS 可能在调用 dealloc 前清空全部应用程序的内存。
当用 setter 给对象赋值时,请小心下面的语句:
[self setName:[[NSString alloc] init]];
name 的设置是正确的但 alloc 没有相应的释放,下面的方式要好一些:
NSString* s = [[NSString alloc] init];
[self setName:s];
[s release];
或者使用自动释放:
[self setName:[[[NSString alloc] init] autorelease]];
自动释放池
自动释放池释放位于分配和 drain 函数之间的对象。
我们在下面的函数中设置一个循环,在循环中将 NSNumber 的一个副本赋给 magicNumber,另外将 magicNumber 设置为自动释放。在这个例子中,我们希望在每次迭代时清空自动释放池(这样可以在赋值的数量很大时节省循环的内存)
- (void) Test
{
NSString* clientName = nil;
NSNumber* magicNumber = nil;
for (int i = 0; i < 10; ++i)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
magicNumber = [[self GetMagicNumber] copy];
[magicNumber autorelease];
if (i == [magicNumber intValue])
{
clientName = [self GetOutput];
}
[pool drain];
}
if (clientName != nil)
{
NSLog(@"Client Name: %@", clientName);
}
}
这里存在的问题是 clientName 在本地的自动释放池中被赋值和释放,所以当外部的池清空时,clientName 已经被释放了,任何对 clientName 的进一步使用都是没有定义的。
在这个例子中,我们在赋值后保留 clientName,直到结束时再释放它:
- (void) Test
{
NSString* clientName = nil;
NSNumber* magicNumber = nil;
for (int i = 0; i < 10; ++i)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
magicNumber = [[self GetMagicNumber] copy];
[magicNumber autorelease];
if (i == [magicNumber intValue])
{
clientName = [self GetOutput];
[clientName retain];
}
[pool drain];
}
if (clientName != nil)
{
NSLog(@"Client Name: %@", clientName);
[clientName release];
}
}
我们在调用 retain 函数和 release 函数的期间获得 clientName 的所有权。通过添加一对 retain 和 release 的调用,我们就确保 clientName 在明确调用释放前不会被自动释放。
集合
当一个对象被添加进集合时,它就被集合所拥有。在这个例子中我们分配一个串,它现在有了所有者;
NSString* str = [[NSString alloc] initWithString:@"Bruce Wayne"];
然后我们将它添加进数组,现在它有两个所有者:
[array addObject: str];
我们可以安全的释放这个串,使其仅被数组所有:
[str release];
赞助商链接