开发者

Leak in NSMutableArray category that returns array filled with NSNull

I currently have a NSMutableArray category that creates a NSMutableArray propagated with NSNulls. When I run this code in Instruments it tells me I have a leak here (read comment to see where)

#import "NSMutableArray+NSNull.h"


@implementation NSMutableArray (NSNull)

-(id)initWithNullCapacity:(int)capacity{

    self = [super init];
    if (self) {
        //Leak on [self init]
        NSMutableArray *array = [self init];

        for (unsigned i = 0; i < capacity; i++)
        {
            [array addObject:[NSNull null]];
        }
        self = array;
    }
    return self;
}

EDIT:

This is where I invoke the method:

#import "TWVStatData.h"
#import "NSMutableArray+NSNull.h"

@implementation TWVStatData

@synthesize creationTime;
@synthesize graphs;
@synthesize elements;
@synthesize type;

-(id)init{
    if(self == [super init]){
        type = -1;

        creationTime = [[NSDa开发者_高级运维te alloc] init];

        graphs = [[NSMutableArray alloc] initWithNullCapacity:3];
        elements =[[NSMutableArray alloc] init];
    }
    return self;
}


This is going to be tricky, primarily because of how NSArray works underneath. I would recommend doing this:

- (id)initWithNullCapacity:(NSUInteger)capacity {
  NSMutableArray *nulls = [NSMutableArray array];
  for (NSUInteger i = 0; i < capacity; i++) {
    [nulls addObject:[NSNull null]];
  }
  return [self initWithArray:nulls];
}

I think the problem is stemming from the assignment to self, though I'm not sure of that. NSArray does some funky optimizations under the hood, and so I would avoid calling an NSArray initializer until after you have all your data ready to go.


You are not creating a sub-class of NSMutableArray, just adding a category, therefore calling [super init] will call the NSArray and not the NSMutableArray initializer, whetever it does which i would call just in case it does something important.

Also, as Ravin mentioned, setting self = without calling [self release] first will leak the previous object, which was returned from the alloc call one level up in the call stack.

This is what you should do:

-(id)initWithNullCapacity:(int)capacity
{
    self = [self initWithCapacity:capacity];
    if (self) 
    {
        for (int i = 0; i < [self count]; i++)
        {
            [self addObject:[NSNull null]];
        }
    }
    return self;
}    


Yes it will because at first line

self = [super init];

you are creating one object(self) and at self = array; you are de-referencing self and reassigning it. so earlier value is in leak.


-(id)initWithNullCapacity:(int)capacity
{
    self = [super init];
    if (self) {
        for (unsigned i = 0; i < capacity; i++)
        {
            [self addObject:[NSNull null]];
        }
    }
    return self;
}

should do the job

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜