Выпуск с NSMutableArray? - PullRequest
       19

Выпуск с NSMutableArray?

0 голосов
/ 16 декабря 2009

Я размещаю myMDD в main, который содержит переменную экземпляра NSMutableArray (alloc / init-ed в init). Когда я добавляю элементы в NSMutableArray (frameList), я освобождаюсь после добавления. Массив и содержащиеся в нем объекты освобождаются в нижней части main.

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    MDD *myMDD = [[MDD alloc] init];
    Frame *myFrame = [[Frame alloc] init];

    [myMDD addFrame:myFrame];

    [myMDD release];
    [pool drain];
    return 0;
}

// METHOD_ mdd addFrame:
-(void)addFrame:(Frame*) inFrame {
    [frameList addObject:inFrame];
    [inFrame release];
}

// METHOD_ mdd dealloc
-(void)dealloc {
    NSLog(@"_deal...: %@", self);
    [frameList release];
    [super dealloc];
}

Мой вопрос заключается в том, что «статический анализатор» сообщает о потенциальной утечке памяти, предпочитая, чтобы релиз для фрейма добавлялся основной. (То есть)

 int main (int argc, const char * argv[]) {

    ...

 [myFrame release]; // Added
    [myMDD release];
    [pool drain];
    return 0;
}

// METHOD_ mdd addFrame:
-(void)addFrame:(Frame*) inFrame {
    [frameList addObject:inFrame];
    // [inFrame release];
}

Я понимаю, почему это так, если я выделяю myMDD и никогда не вызываю addFrame, тогда мне нужно его освободить. Может быть, это просто случай добавления автоматического выпуска к myMDD, но сработает ли это в ситуации, когда я вызываю addFrame, а NSMutableArray освобождает объект?

EDIT_001

Изменено на ...

int main (int argc, const char * argv[]) {
    ...
    [myMDD addFrame:myFrame];
    [myFrame release];
    myFrame = nil;

    [myMDD release];
    [pool drain];
    return 0;
}

// METHOD_ mdd addFrame:
-(void)addFrame:(Frame*) inFrame {
    [frameList addObject:inFrame];
}

* 1014 Гэри *

Ответы [ 3 ]

2 голосов
/ 16 декабря 2009

Причина, по которой вы получили это предупреждение, заключается в том, что NSMutableDArray сохраняет любой объект, помещенный в него; аналогично, когда NSMutableArray освобождается, он также освобождает любой объект, содержащийся в нем. Итак, давайте посмотрим на ваш код.

Эта строка:

Frame *myFrame = [[Frame alloc] init];

создает новый экземпляр Frame с именем myFrame. myFrame имеет счет сохранения 1, потому что вы использовали alloc / init для его создания.

Затем вы передаете это addFrame::

[myMDD addFrame:myFrame];

Что, в свою очередь, помещает его в экземпляр NSMutableArray:

[frameList addObject:inFrame];

В этот момент inFrame и myFrame указывают на один и тот же объект. При добавлении в массив значение сохранения этого объекта увеличивается, поэтому теперь оно равно 2.

Позже, обратно в main, вы выпускаете myMDD, который выпускает frameList. Предполагая, что frameList теперь имеет счет сохранения 0, он освобождается - и, как NSMutableArray, он освобождает любой содержащийся в нем объект, включая объект, указанный на моем myFrame.

Так что теперь счетчик хранения myFrame равен 1 ... поэтому он не освобождается, и у вас есть утечка памяти.

Один из способов решения проблемы с помощью Cocoa-y - авто-релиз myFrame:

Frame *myFrame = [[[Frame alloc] init] autorelease];

Что означает, что он не протечет. Затем используйте метод -[MDD dealloc] во втором примере (Edit_001). Вы правы, что вы не должны выпускать inFrame в вашем addFrame методе, поскольку вы его не сохраняете.

1 голос
/ 16 декабря 2009

В большинстве случаев Какао предоставляет методы класса, которые инициализируют и возвращают автоматически выпущенную версию объекта. т.е. [NSMutableDictionary dictionary] против [[NSMutableDictionary alloc] init].

Я советую всегда использовать методы класса, где это возможно, если вы создаете объект, который вам не нужно хранить, или если вы собираетесь хранить его в коллекции (NSArray, NSDictionary, NSSet и т. Д.).

Таким образом, общее правило заключается в том, чтобы выделять только объекты, принадлежащие вашему классу напрямую (т.е. переменную instace или class, а не внутри коллекции), и использовать методы класса для всех остальных случаев.

1 голос
/ 16 декабря 2009

В соответствии с соглашением, метод add должен просто сохранять объект при необходимости, а не освобождать его. И, как правило, вы не должны освобождать объект, который вы не сохранили, в вашем примере область, в которой вы сохранили (создали) фрейм, отличается от области действия метода addFrame.

Под областью я подразумеваю область логики, а не область языка.

В этом конкретном примере вы должны вызывать release сразу после addFrame. Но релиз не должен быть в методе addFrame.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...