Il semble que la façon dont vous le faites devrait probablement fonctionne bien, mais c'est une façon un peu étrange de s'y prendre.
Si vous pouvez exiger OS X 10.6+, votre code pourrait être consolidée à ce qui suit:
//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];
}
Notez que par l'ajout d'un autorelease
lors de la création du NSMenuItem
dans la boucle inférieure, il n'y a pas besoin pour envoyer le release
supplémentaire lors de la suppression de l'élément de menu comme dans votre code. Dans un certain sens, un NSMenu
agit comme un NSArray
avec les sous-menus et les éléments de menu qu'il contient: il les conserve. Donc, puisque vous insérez le NSMenuItem
nouvellement créé directement dans le NSMenu
, c'est comme si le NSMenu
prenait possession de l'élément de menu. En tant que tel, vous devez contrer le compte de retenue +1 que vous obtenez de la création alloc/init de l'élément pour vous assurer que vous n'obtenez pas de fuite de mémoire. Dans votre code, vous étiez en train de neutraliser le fait que +1 conserve le compte en lui envoyant une version explicite/supplémentaire lors du retrait de l'élément de menu, ce qui est un peu un rond-point. Dans le code ci-dessus que j'ai posté, en ajoutant le autorelease
lors de la création dans la boucle inférieure, la seule chose "tenant à" les éléments du menu sera le menu. Ensuite, plus tard, lorsque vous appelez la méthode removeAllItems
, le menu envoie un release
à chaque élément de menu, auquel point leur nombre de rétention doit être réduit à 0 et ils seront désalloués.
Si vous devez prendre en charge les versions d'OS X antérieures à 10.6, vous pouvez utiliser le code ci-dessus, sauf le remplacement [statusMenuScansMenu md_removeAllItems]
pour [statusMenuScansMenu removeAllItems]
. Vous pouvez ensuite créer cette méthode md_removeAllItems
dans une catégorie sur NSMenu
comme ceci:
@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
Où est-il dire la fuite de mémoire est? – bryanmac