我对iOS内存管理感到困惑。我有一个类,其成员类型为NSMutableArray。当将此类型的对象存储在另一个阵列中并将其删除时,Instruments会显示所有这些成员都会泄漏内存。这是我的流氓类的定义:
@interface Tester : NSObject {
int some;
NSMutableArray* others;
}
@property int some;
@property (nonatomic, retain) NSMutableArray* others;
-(id)init;
-(id)copy;
-(void)dealloc;
@end
这是流氓类的实现:
@implementation Tester
@synthesize some;
@synthesize others;
-(id)init {
self = [super init];
if(self) {
some = 0;
others = [[NSMutableArray alloc] initWithCapacity:5];
int i;
for(i = 0; i < 5; ++i) {
[others addObject:[NSNumber numberWithInt:i]];
}
}
return self;
}
-(id)copy {
Tester* cop = [[Tester alloc] init];
cop.some = some;
cop.others = [others mutableCopy]
return cop;
}
-(void)dealloc {
[others removeAllObjects];
[others release];
[super dealloc];
}
@end
以下是我测试的方法:
NSMutableArray* container = [[NSMutableArray alloc] init];
Tester* orig = [[Tester alloc] init];
int i;
for(i = 0; i < 10000; ++i) {
Tester* cop = [orig copy];
[container addObject:cop];
}
while([container count] > 0) {
[[container lastObject] release];
[container removeLastObject];
}
[container release];
运行此代码会泄漏内存,而Instruments会显示泄漏的内存分配在以下行:
cop.others = [others mutableCopy];
我做错了什么?
答案 0 :(得分:4)
您正在创建一个副本:[others mutableCopy]
您拥有但忘记发布。该行应该是:
cop.others = [[others mutableCopy] autorelease];
如果您让container
数组成为Tester
对象的唯一所有者,那么测试代码会更清晰:
NSMutableArray* container = [[NSMutableArray alloc] init];
Tester* orig = [[Tester alloc] init];
for (int i = 0; i < 10000; ++i)
[container addObject:[[orig copy] autorelease]];
while([container count] > 0)
[container removeLastObject];
[container release];
现在你可以删除清空容器的循环。
或者你可以跳过容器:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Tester* orig = [[[Tester alloc] init] autorelease];
for (int i = 0; i < 10000; ++i)
[[orig copy] autorelease];
[pool drain]; // At this point all Tester objects are released
答案 1 :(得分:3)
cop.others = [others mutableCopy]
其他人被宣布为保留财产,因此分配给新财产的所有权声明。 -mutableCopy是一种暗示所有权的方法(因为它包含单词“copy”)。因此,您现在拥有两个所有权声明,这两个声明都必须发布。建议的方法是首先将副本分配给临时变量,然后将其分配给您的属性并释放它,如下所示:
NSMutableArray *tmpArray = [others mutableCopy];
cop.others = tmpArray;
[tmpArray release];
您也可以一步完成此操作,避免临时对象,尽管这样做会使用自动释放池,因此效率稍低:
cop.others = [[others mutableCopy] autorelease];