Как освободить объект в цикле forin? - PullRequest
7 голосов
/ 23 марта 2011

Я новичок в какао / target-c, и я борюсь с выпуском своих объектов. У меня есть следующий код:

gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
    NSString *oid = [gastrocategory objectForKey:@"id"];
    GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:@"name"]];
    [gastroCategoryList addObject:gc];
}

Анализатор показывает мне, что "гастрокатегория", определенная в for, является потенциальной утечкой памяти. Но я не уверен, смогу ли я выпустить это в конце цикла for?

Также по следующему коду:

- (NSArray *)eventsForStage:(int)stageId {

    NSMutableArray *result = [[NSMutableArray alloc] init];

    for (Event *e in eventList) {
        if ([e stageId] == stageId) {
            [result addObject:e];
        }
    }

    return result;
}

Анализатор говорит мне, что мой "результат" - это потенциальная утечка. Но где я должен выпустить это?

Существует ли простое правило для запоминания, когда я должен использовать метод присвоения, копирования, сохранения и т. Д. В @property?

Другая проблема:

- (IBAction)showHungryView:(id)sender {
    GastroCategoriesView *gastroCategoriesView = [[GastroCategoriesView alloc] initWithNibName:@"GastroCategoriesView" bundle:nil];

    [gastroCategoriesView setDataManager:dataManager];

    UIView *currentView = [self view];
    UIView *window = [currentView superview];

    UIView *gastroView = [gastroCategoriesView view];

    [window addSubview:gastroView];

    CGRect pageFrame = currentView.frame;
    CGFloat pageWidth = pageFrame.size.width;
    gastroView.frame = CGRectOffset(pageFrame,pageWidth,0);

    [UIView beginAnimations:nil context:NULL];
    currentView.frame = CGRectOffset(pageFrame,-pageWidth,0);
    gastroView.frame = pageFrame;
    [UIView commitAnimations];

    //[gastroCategoriesView release];
}

Я не понимаю, "gastroCategoriesView" - это потенциальная утечка. Я попытался выпустить его в конце или с авто-выпуском, но ни один не работает нормально. Каждый раз, когда я вызываю метод, мое приложение завершается. Еще раз большое спасибо!

Ответы [ 3 ]

9 голосов
/ 23 марта 2011

В вашем цикле отпустите каждый gc после добавления его в список, так как он вам больше не понадобится в области видимости вашего цикла:

gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
    NSString *oid = [gastrocategory objectForKey:@"id"];
    GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:@"name"]];
    [gastroCategoryList addObject:gc];
    [gc release];
}

В вашем методе объявите result какавтоматически освобожден для освобождения владельца от вашего метода:

NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];

// An alternative to the above, produces an empty autoreleased array
NSMutableArray *result = [NSMutableArray array];

РЕДАКТИРОВАТЬ: в вашем третьем выпуске вы не можете освободить контроллер представления, потому что его представление используется окном.Установка его на автоматический выпуск также вызывает ту же участь, только с задержкой.

Вам нужно будет где-то сохранить свой контроллер GastroCategoriesView, например, в переменной экземпляра вашего делегата приложения.

3 голосов
/ 23 марта 2011

Ответ BoltClock точен на первую часть вашего вопроса. Я постараюсь заняться остальным.

Назначение для простых необъектных типов, таких как int, double или struct. Он генерирует установщик, который выполняет простое старое назначение, как в "foo = newFoo". Copy & retain, как и подразумевают их имена, создаст копию нового значения ("foo = [newFoo copy]") или сохранит его ("foo = [newFoo retain]"). В обоих случаях установщик сбросит старое значение соответствующим образом.

Таким образом, вопрос в том, когда копировать, а когда сохранять. Ответ ... это зависит. Как ваш класс использует новое значение? Ваш класс сломается, если какой-то другой код изменяет входящий объект? Скажем, например, у вас есть свойство NSString * с художественным названием «theString». Другой код может назначить экземпляр NSMutableString для String - это законно, потому что это подкласс NSString. Но этот другой код может также сохранять собственную ссылку на изменяемый строковый объект и изменять его значение - готов ли ваш код справиться с такой возможностью? Если нет, он должен сделать свою собственную копию, которую другой код не может изменить.

С другой стороны, если ваш собственный код не делает предположений о том, могла ли быть изменена строка, и работает так же хорошо, независимо от того, было ли это, то вы бы сэкономили память, сохранив входящий объект вместо ненужного создания копия этого.

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

1 голос
/ 23 марта 2011

Причина, по которой вы можете освободить gc после его добавления в gastroCategoryList, заключается в том, что при добавлении объекта в массив массив сохраняет этот объект.Так что, даже если вы отпустите свой gc, он все равно будет;сохраняется посредством gastroCategoryList.

Когда вы возвращаете вновь созданный объект из метода, вам нужно вызвать autorelease. Это приведет к тому, что объект будет освобожден только после того, как среда выполнения выйдет из области действия вызывающего метода,тем самым давая вызывающему методу шанс что-то сделать с возвращаемым значением.

Обратите внимание, что если ваш метод начинается со слова copy или new, то вы должны , а не автоматически высвобождать ваш объект;Вы должны оставить это для вызывающего метода для освобождения.

Что касается копирования vs retain vs assign ... как правило, копируйте объекты с изменяемой версией, такие как NSArray, NSSet, NSDictionary и NSString,Это гарантирует, что объект, на который у вас есть указатель, не будет изменяемым, если вы не хотите, чтобы он был.

В противном случае используйте retain всякий раз, когда вы хотите, чтобы ваш класс гарантировал, что объект все еще находится в памяти.Это будет применяться почти к каждому объекту, за исключением объектов, которые считаются родителями вашего объекта, и в этом случае вы бы использовали метод assign.(См. Раздел о циклах сохранения здесь ).

Также обратите внимание, что вы должны использовать assign для необъектных типов, таких как int.

Чтение через память Руководство по программированию управления немного;это очень полезно.

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