2009-11-18 3 views
2

Je reçois des rapports de fuites de mémoire dans mon application, mais je ne peux pas savoir exactement ce qui se passe. J'ai une fonction qui sort une vieille vue et permute dans une nouvelle vue. Je n'utilise pas NavControllers ni aucune @properties; Je gère directement ma fenêtre de haut niveau.Suivi des fuites de mémoire de cacao

-(void)swapInView:(UIViewController*)newViewController 
{ 
    [currentViewer.view removeFromSuperview]; 
    printf("Old viewController (%p) has count of %d; now releasing\n", 
     currentViewer, [currentViewer retainCount]); 
    [currentViewer release]; 
    currentViewer = 0; 

    currentViewer = newViewController; 
    [currentViewer retain]; 

    [mainWindow addSubview:currentViewer.view]; 
    [mainWindow bringSubviewToFront:currentViewer.view]; 
} 

Quand exécuter le code, je montre que le contrôleur d'affichage actuel est désallouée, et ma méthode dealloc pour ce contrôleur de vue est appelé se. Mais, Instruments/leaks le signale toujours comme une fuite. Par exemple, je reçois cette copie papier:

Old viewController (0x119f80) has count of 1; now releasing 
Deallocating WelcomeScreenViewController 

Je peux vérifier à l'adresse, que ce soit le même objet alloué précédemment.

Mon code externe ressemble à ceci:

MyViewController *theViewController = [[MyViewController alloc] 
             initWithNibName:nil 
               bundle:nil]; 
[GameMaster swapInNewView:theViewController]; 
[theViewController release]; 

Quelqu'un at-il des suggestions sur la façon de traquer ce qui se passe? J'utilise le SDK 3.1.2, mais je le voyais aussi sur les SDK précédents.

+0

Quelle est la ligne spécifique des Instruments qui fuit? –

+0

[mainWindow addSubview: currentViewer.view]; –

+0

Il semble donc que 'mainWindow' fuit une sous-vue ajoutée. Appelez-vous release sur 'mainWindow' à un moment donné? –

Répondre

3

Huh. C'était amusant. J'ai écrit un test rapide pour m'assurer qu'aucun d'entre nous n'était fou.

En fin de compte, tout se résume au code d'appel:

[[MyViewController alloc] initWithNibName:nil bundle:nil]; 

Lorsque vous initialisez un contrôleur de vue, son objet view n'a pas encore été défini, et ne sera pas défini jusqu'à ce que la demande.

Puisque vous spécifiez nil pour le nom de la plume, vous devez remplacer loadView dans votre sous-classe UIViewController afin de définir correctement l'objet de la vue. Voir Apple's documentation pour plus de détails.

La mise en œuvre par défaut de loadView semble faire de la magie dans les coulisses, et cette magie peut entraîner une fuite de mémoire.

Donc: quand vous faites cet appel:

[mainWindow addSubview:currentViewer.view]; 

Vous faites réellement deux appels:

One: currentViewer.view, qui se traduit par un appel à [currentViewer loadView] et
Deux: [mainWindow addSubview:...] , qui tente d'ajouter la vue nouvellement chargée. Leaks identifie cette ligne en raison du premier appel, et non du second.

Pour vérifier, il suffit de modifier la méthode loadView dans vos sous-classes personnalisées UIViewController:

- (void)loadView 
{ 
    [self setView:[[UIView new] autorelease]]; 
} 

Cela empêche l'appel à la valeur par défaut loadView et maintenant il n'y a plus de fuites.

De toute évidence, une fois que vous aurez développé cette application, vous devrez soit mettre quelque chose de plus significatif dans loadView, soit utiliser des pointes.

+0

Fantastique! Cela semble avoir arrangé les choses. Il finit (j'ai inconsciemment copié ceci de l'exemple de code d'Apple) que si vous passez "nil" dans initWithNibName, il cherchera un fichier nib avec le même nom que la classe et le chargera. Mais, apparemment, il fuit la mémoire aussi ... –

0

Notez la documentation relative à la méthode removeFromSuperview:

« délie le récepteur de sa superview et sa fenêtre, il supprime de la chaîne de répondeur, et invalident ses rectangles de curseur Le récepteur est également libéré. ​​»

Je ne sais pas si cela est votre problème ou non, mais cela:

[exampleViewController.view removeFromSuperview]; 
[exampleViewController release]; 

Dans mon application provoque un accident retardé en raison de plus libérant un objet.

+0

vrai, mais je conserve le viewController moi-même quand je le règle, puis relâchez après je l'ai enlevé, donc je ne plante pas. –