如何正确释放带有 NSMutableArray 成员且内部有 NSNumber 对象的对象的 NSMutableArray?

发布于 2024-10-29 06:43:59 字数 1379 浏览 3 评论 0原文

我对 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];

运行此代码会泄漏内存,仪器显示泄漏的内存是在以下行分配的:

cop.others = [others mutableCopy];

我做错了什么?

I'm puzzled about iOS memory management. I have a class that has a member of type NSMutableArray. When storing objects of this type in another array and removing them, Instruments shows that all those members leak memory. Here's the definition of my rogue class:

@interface Tester : NSObject {
  int some;
  NSMutableArray* others;
}
@property int some;
@property (nonatomic, retain) NSMutableArray* others;
-(id)init;
-(id)copy;
-(void)dealloc;
@end

Here's the implementation of the rogue class:

@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

And here's how I test it:

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];

Running this code leaks memory and Instruments shows that the leaked memory is allocated at line:

cop.others = [others mutableCopy];

What have I done wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

恬淡成诗 2024-11-05 06:43:59

您正在创建一个副本:[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

You are creating a copy: [others mutableCopy] which you own but forget to release. The line should be:

cop.others = [[others mutableCopy] autorelease];

You testing code would be clearer if you'd let the container array be the sole owner of the Tester objects:

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];

Now you could remove the loop that empties the container.

Or you could just skip the container:

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
紫罗兰の梦幻 2024-11-05 06:43:59
cop.others = [others mutableCopy]

其他的被声明为保留财产,因此分配给它会建立对新价值的所有权主张。 -mutableCopy 是一种暗示所有权的方法(因为它包含“复制”一词)。因此,您现在有两个所有权主张,两者都必须被释放。建议的方法是首先将副本分配给临时变量,然后将其分配给您的属性并释放它,如下所示:

NSMutableArray *tmpArray = [others mutableCopy];
cop.others = tmpArray;
[tmpArray release];

您也可以一步完成此操作,避免临时对象,尽管这样做使用自动释放池,效率稍低,因为:

cop.others = [[others mutableCopy] autorelease];
cop.others = [others mutableCopy]

Others is declared as a retained property, so assigning to it establishes an ownership claim on the new value. -mutableCopy is a method that implies ownership (because it contains the word "copy"). So you now have two claims of ownership, both of which must be released. The recommended way to do this is to assign the copy first to a temp variable, then assign that to your property and release it, like so:

NSMutableArray *tmpArray = [others mutableCopy];
cop.others = tmpArray;
[tmpArray release];

You could also do this in one step, avoiding the temp object, although doing so uses the autorelease pool and is slightly less efficient because of that:

cop.others = [[others mutableCopy] autorelease];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文