Управление памятью при обновлении элементов в NSMenu
Я хотел бы знать, если это правильный способ избежать утечки памяти в приложении Какао.
Мое приложение имеет метод, который обновляет NSMenu
предметы:
//Remove and Release old Status Scan Menu:
if ([statusMenuScansMenu numberOfItems] !=0) {
for (NSMenuItem *menueItemToBeReleased in [statusMenuScansMenu itemArray]) {
[statusMenuScansMenu removeItem:menueItemToBeReleased];
[menueItemToBeReleased release];
}
}
//New Status Scan Menu:
for (MyObject* myObject in myArray) {
NSMenuItem * scanMenuItem = [[NSMenuItem alloc] init];
[scanMenuItem setTitle:[myObject name]];
[statusMenuScansMenu addItem:scanMenuItem];
}
Как видите, перед добавлением новых элементов я удаляю все предыдущие элементы и отправляю release
им. Затем я добавляю новые.
Это лучший способ для управления памятью?
Если я анализирую свой код в Xcode 4.1, он говорит, что существует потенциальная утечка памяти.
1 ответ
Похоже, что вы делаете это, вероятно, должно работать хорошо, но это своего рода странный способ сделать это.
Если вам может потребоваться OS X 10.6+, ваш код может быть сведен к следующему:
//Remove old Status Scan Menu:
[statusMenuScansMenu removeAllItems];
//New Status Scan Menu:
for (MyObject* myObject in myArray) {
NSMenuItem * scanMenuItem = [[[NSMenuItem alloc]
initWithTitle:[myObject name] action:NULL keyEquivalent:@""] autorelease];
[statusMenuScansMenu addItem:scanMenuItem];
}
Обратите внимание, что добавив autorelease
при создании NSMenuItem
в нижней петле, нет необходимости отправлять лишние release
во время удаления пункта меню, как в вашем коде. В каком-то смысле NSMenu
действует как NSArray
делает с подменю и пунктами меню, которые это содержит: это сохраняет их. Так как вы вставляете недавно созданный NSMenuItem
прямо в NSMenu
это как будто NSMenu
берет на себя ответственность за пункт меню. Таким образом, вам нужно противодействовать счету удержания +1, который вы получаете при создании alloc/init элемента, чтобы убедиться, что вы не получите утечку памяти. В вашем коде вы противодействовали тому, что +1 сохраняет счет, посылая ему явный / дополнительный релиз во время удаления пункта меню, что является своего рода обходным путем. В приведенном выше коде, который я разместил, добавив autorelease
во время создания в нижнем цикле единственное, что "держится" за пункты меню - это меню. Затем, позже, когда вы звоните removeAllItems
метод, меню отправит release
для каждого пункта меню, в этот момент их счетчик хранения должен упасть до 0, и они будут освобождены.
Если вам необходимо поддерживать версии OS X до 10.6, вы можете использовать приведенный выше код, за исключением замены [statusMenuScansMenu md_removeAllItems]
за [statusMenuScansMenu removeAllItems]
, Вы можете создать это md_removeAllItems
метод в категории на NSMenu
вот так:
@interface NSMenu (MDAdditions)
- (void)md_removeAllItems;
@end
@implementation NSMenu (MDAdditions)
- (void)md_removeAllItems {
NSUInteger currentCount = [self numberOfItems];
for (NSUInteger i = 0; i < currentCount; i++) {
[self removeItemAtIndex:0];
}
}
@end