2011-10-08 1 views
1

Je voudrais savoir si c'est la bonne façon d'éviter une fuite de mémoire dans une application Cocoa.Gestion de la mémoire lors de la mise à jour des éléments dans un NSMenu

Mon application a une méthode qui met à jour un des éléments de 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]; 
} 

Comme vous pouvez le voir, avant d'ajouter de nouveaux articles que je supprimer tous les éléments précédents et envoyer release à eux. Ensuite, j'ajoute les nouveaux.

Est-ce la meilleure façon de gérer la mémoire?

Si j'analyse mon code dans Xcode 4.1, il est indiqué qu'il existe une fuite de mémoire potentielle.

+1

Où est-il dire la fuite de mémoire est? – bryanmac

Répondre

5

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 
+1

Vous n'avez pas besoin d'utiliser la libération automatique. Au lieu de cela, allouer/init les objets, les ajouter au menu, puis les relâcher. Cela élimine le besoin d'un pool autorelease à mettre en place, qui, bien qu'il devrait toujours être, il ya quelque chose que l'iPhone aime parfois à éviter de se remplir. –

+4

@ user256413: Utiliser autorelease, surtout comme une habitude, rend beaucoup plus difficile d'oublier la sortie. Sur le Mac, où il n'y a aucun risque (actuellement) que le système d'exploitation tue votre processus pour allouer trop d'éléments de menu à la fois, il est préférable de ne pas risquer de fuir. –

+0

Merci beaucoup pour cette réponse détaillée !!! – Daniel

Questions connexes