Утечка в категории NSMutableArray, которая возвращает массив, заполненный NSNull

#iphone #ios #memory-management #memory-leaks

#iPhone #iOS #управление памятью #утечки памяти

Вопрос:

В настоящее время у меня есть категория NSMutableArray, которая создает NSMutableArray, распространяемый с помощью NSNulls. Когда я запускаю этот код в Инструментах, он сообщает мне, что у меня здесь утечка (прочитайте комментарий, чтобы узнать, где)

 #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;
}
  

Редактировать:

Здесь я вызываю метод:

 #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 = [[NSDate alloc] init];

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

Ответ №1:

Это будет сложно, в первую очередь из-за того, как NSArray работает под ним. Я бы рекомендовал сделать это:

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

Я думаю, что проблема связана с присвоением self , хотя я не уверен в этом. NSArray выполняет некоторые сложные оптимизации под капотом, и поэтому я бы не вызывал NSArray инициализатор до тех пор, пока после вас все ваши данные не будут готовы к отправке.

Комментарии:

1. Когда я запускаю ваш код в Инструментах, я получаю ошибку при возврате строки [self initWithArray: nulls]; После проб и ошибок мне удалось исправить это с помощью реализации, которую я опубликовал в качестве ответа.

2. @Cyprian тогда вы делаете что-то неправильно, потому что, когда я использую это изолированным образом, оно отлично работает без утечек.

3. 1 выглядит неплохо, но я полагаю, что цена удерживает в памяти 2 массива вместо одного на некоторое время, не то чтобы я думаю, что это вызовет какие-либо реальные последствия

Ответ №2:

Вы не создаете подкласс NSMutableArray, просто добавляя категорию, поэтому вызов [super init] вызовет NSArray, а не инициализатор NSMutableArray, независимо от того, выполняет ли он, который я бы вызвал на всякий случай, если он делает что-то важное.

Также, как упоминал Равин, установка self = без вызова [self release] сначала приведет к утечке предыдущего объекта, который был возвращен из вызова alloc на один уровень выше в стеке вызовов.

Это то, что вы должны сделать:

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

Комментарии:

1. Когда я делаю то, что вы предлагаете, инструменты сообщают мне, что у меня утечка в строке self = [self initWithCapacity:емкость];

2. @Cyprian не могли бы вы опубликовать код, использующий этот метод? В этом действительно не должно быть ничего плохого…

3. вы правы, у меня возникла ошибка при инициализации объекта выше в иерархии и не освобождении его, что привело к утечке объекта на нижнем уровне.

Ответ №3:

Да, это произойдет, потому что в первой строке

 self = [super init];
  

вы создаете один объект ( self ) и при self = array; отменяете ссылку self и переназначаете его. таким образом, более раннее значение находится в утечке.

Комментарии:

1. Спасибо, но можете ли вы явно сказать мне, что изменить в методе?

Ответ №4:

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

должно выполнить задание

Комментарии:

1. Ну, когда я это делаю, компилятор выдает мне ошибку: -[NSMutableArray count]: метод, отправленный неинициализированному изменяемому объекту массива