2012-03-10 2 views
1

tout d'abord désolé pour mon anglais :-) pas si bon.étrange fuite de mémoire dans la fenêtre: addSubView

J'ai une fuite de mémoire étrange avec le code suivant (code après l'explication). J'ai une classe, FLWaitingView. C'est une vue simple avec un indicateur d'attente (plus une vue avec arrière-plan), utilisé pour dire à l'utilisateur "attendre que les données soient chargées". Il a deux méthodes simples: montrer et rejeter. Dans la méthode show, je trouve la fenêtre principale de l'application et ajoute les sous-vues (la vue en attente et une vue en arrière-plan, avec différentes animations). Dans la méthode de rejet, je l'enlève de superview. Dans chaque spectacle, je vérifie que la vue n'est pas déjà visible en utilisant un booléen statique var (is_visible).

La chose étrange est ceci: Dans le rejeter la méthode, je l'utilise:

[self.view removeFromSuperview]; 
[self.waitingView removeFromSuperview]; 

pour enlever les deux vues de la fenêtre, pour les éviter à retenir. Ils sont correctement supprimés, je peux vérifier cela avec NSLog (pour cicle sur chaque sous-vue de la fenêtre). Mais, dans INSTRUMENTS, en utilisant la fonction "mark heap", je vois que dans chaque rechargement (nouvelle instance de FLWaitingView, puis show, puis rejeter) l'ancienne instance reste en mémoire et continue d'augmenter l'utilisation de la mémoire. est évidemment pas un problème du code d'appel, parce que je libère correctement l'objet:

//CALLING CODE 
//customWaitingView is a property retained 
self.customWaitingView = [[[FLWaitingView alloc]init]autorelease]; 
[self.customWaitingView show]; 

De plus, et je pense que c'est l'information la plus importante, si je déplace la dismission vue dans une autre méthode, appelée par un sélecteur, la fuite disparait !!!

Maintenant, je montre le "mauvais" code et, après, la "correction". Je voudrais comprendre pourquoi cela arrive.

- (void)show 
{ 

    if (!is_visible){ 

     id appDelegate = [[UIApplication sharedApplication] delegate]; 
     UIWindow *window = [appDelegate window]; 
     self.waitingLabel.text = @"Attendere"; 

     self.view.alpha = 1.0; 
     self.waitingView.alpha = 1.0; 

     [window addSubview:self.view]; 
     [window addSubview:self.waitingView]; 
     [self.waitingIndicator startAnimating]; 
     self.view.frame = window.frame; 
     self.waitingView.center = window.center; 
     // "Pop in" animation for alert 
     [self doPopInAnimationWithDelegate:self]; 
     // "Fade in" animation for background 
     [self doFadeInAnimation]; 
     is_visible = YES; 
    } else { 
     NSLog(@"FLWaitingView %@ already visible, do nothing", self); 
    } 

} 


- (void)dismiss 
{ 
    [UIView beginAnimations:nil context:nil]; 
    self.view.alpha = 0.0; 
    self.waitingView.alpha = 0.0; 
    [UIView commitAnimations]; 
    [self.waitingIndicator stopAnimating]; 

    //here is the problem 
    [self.view removeFromSuperview]; 
    [self.waitingView removeFromSuperview]; 
    is_visible = NO; 
} 

le code ci-dessus est le « mauvais », mais si j'ajoute

[self performSelector:@selector(alertDidFadeOut) withObject:nil afterDelay:0.5]; 

dans le rejeter la méthode et une nouvelle méthode (suppression de toute évidence le code redondant de rejeter la méthode):

- (void)alertDidFadeOut 
{  
    //here the memory is correctly released 
    [self.view removeFromSuperview]; 
    [self.waitingView removeFromSuperview]; 
    is_visible = NO; 
} 

la mémoire est correctement libérée. Pourquoi ?????? Nous vous remercions à l'avance

Fabio

Répondre

0

Votre vue ne reçoit pas libéré comme vous seriez attendiez parce qu'à ce moment vous relâcher il y a encore des animations qui y sont liées. Vous ne pouvez le relâcher correctement qu'une fois les animations terminées.

Votre deuxième méthode fonctionne parce que l'animation dure moins de 0,5 seconde - le code de libération est appelé après que la vue est libérée de toutes les animations.

Une bonne façon d'animer le point de vue serait soit de créer une animation et assigner son délégué ou peut-être un peu de Soulution plus élégante est d'utiliser l'animation à base de blocs comme ceci:

- (void)dismiss 
{ 

    [[UIApplication sharedApplication] beginIgnoringInteractionEvents];        

    [UIView animateWithDuration: 0.15 
     animations: ^{ 
      self.view.alpha = 0.0; 
      self.waitingView.alpha = 0.0; 
        } 
     completion: ^(BOOL finished){ 
      [self.waitingIndicator stopAnimating]; 
      [self.view removeFromSuperview]; 
      [self.waitingView removeFromSuperview]; 
      is_visible = NO;  
      [[UIApplication sharedApplication] endIgnoringInteractionEvents];        
     }]; 
} 
+0

cela fonctionne aussi (pas de mémoire fuite), comme mon autre "workaroud", mais je ne comprends pas pourquoi :-). Quel est le problème dans le premier code? les vues semblent être correctement enlevées de la fenêtre principale ... mais pas libérées ... – LombaX

+0

@LombaX: j'ai édité ma réponse avec quelques explications –

+0

Merci beaucoup! Maintenant, je comprends :-) passer à l'animation en bloc !! – LombaX