[obj-c] NSTimer qui target self et retain cycles

colas_colas_ Membre
juin 2015 modifié dans Objective-C, Swift, C, C++ #1

Bonjour,


 


j'ai enfin trouvé ma fuite de mémoire !!


 


J'ai un View Controller qui sa méthode d'initialisation fait :



[NSTimer scheduledTimerWithTimeInterval:kTimeBeforeUpdatingTheBlurredView
target:self
selector:@selector(updateBlurredView)
userInfo:nil
repeats:YES] ;

Mon VC n'est alors jamais désavoué. Je pense que c'est parce que :


1) le timer retient self


2) le timer, qui est en mode repeat, est retenu par NSLoop


 


 


Du coup, self est toujours retenu.


 


 


J'ai vu une solution sur SO, qui consiste à  créer un proxy pour l'objet à  retenir :



[...]
@implementation BTWeakTimerTarget
{
__weak target;
SEL selector;
}

[...]

- (void)timerDidFire:(NSTimer *)timer
{
if(target)
{
[target performSelector:selector withObject:timer];
}
else
{
[timer invalidate];
}
}
@end

Je pense qu'il s'agit d'un problème classique alors je voulais avoir vos lumières !!!


 


 


 


Réponses

  • PS : une autre solution pour moi serait


     


    -> je peux invalider mon timer et le relancer dans viewWillApper et viewWillDisappear


    -> dans ce cas, mon timer doit être une @property (weak), car elle est retain par le NSRunLoop


    -> Je le crée (et la launche) dans -viewWillApper et l'invalidate dans -viewWillDisappear


     


    Est-ce que j'ai tout bon ?


     


    Merci !


     


     


    PPS : L'avantage de la première solution est qu'elle marche tout le temps, pas que pour les VC qui ont des méthodes viewWillAppear or Disappear


  • CéroceCéroce Membre, Modérateur

    -> je peux invalider mon timer et le relancer dans viewWillApper et viewWillDisappear
    -> dans ce cas, mon timer doit être une @property (weak), car elle est retain par le NSRunLoop
    -> Je le crée (et la launche) dans -viewWillApper et l'invalidate dans -viewWillDisappear
     
    Est-ce que j'ai tout bon ?

    Oui.

    PPS : L'avantage de la première solution est qu'elle marche tout le temps, pas que pour les VC qui ont des méthodes viewWillAppear or Disappear

    Sur mon projet actuel, j'ai dû créer mon propre timer basé sur GCD pour cette raison, mais c'est un cas très particulier; en général tu maà®trises assez le cycle de vie de la target pour pouvoir invalider le timer.
  • MalaMala Membre, Modérateur
    juin 2015 modifié #4


    Bonjour,


     


    j'ai enfin trouvé ma fuite de mémoire !!


     


    J'ai un View Controller qui sa méthode d'initialisation fait :



    [NSTimer scheduledTimerWithTimeInterval:kTimeBeforeUpdatingTheBlurredView
    target:self
    selector:@selector(updateBlurredView)
    userInfo:nil
    repeats:YES] ;

    Mon VC n'est alors jamais désavoué. Je pense que c'est parce que :


    1) le timer retient self


    2) le timer, qui est en mode repeat, est retenu par NSLoop


     


     


    Du coup, self est toujours retenu.


     


    Je pense qu'il s'agit d'un problème classique alors je voulais avoir vos lumières !!!




     


    Oui c'est un très grand classique. Félicitations, tu as trouvé le piège.  ;)


     


    Les newbies qui font confiance aveugle à  ARC se font d'autant plus facilement avoir qu'il ne réfléchissent pas à  la gestion mémoire.


  • LarmeLarme Membre


    j'ai enfin trouvé ma fuite de mémoire !!




    Moi qui n'ai suivi tous les épisodes, cette fuite mémoire apparaissait dans Instruments/Memory Leak ?


    C'est vrai qu'en y réfléchissant un peu, cela devrait poser quelques problèmes mémoires.


    Sur l'application du boulot actuelle (Legacy code), je me demande s'il n'y a pas ce soucis. Je sais qu'un de mes collègue a fait pas mal de clean ces derniers temps niveau gestion mémoire, mais je vais vérifier que celui-ci n'est pas présent, vu qu'elle est assez lourde et qu'il reste sûrement quelques trucs à  améliorer.

  • Je l'ai trouvée via instruments allocation, mais surtout j'ai overidé -dealloc pour voir que certains objets n'etaient jamais détruits.
  • MalaMala Membre, Modérateur
    juin 2015 modifié #7

    L'info importante qui n'est pas dans la doc de la classe mais dans "Using Timers"...


     



    A timer maintains a strong reference to its target. This means that as long as a timer remains valid, its target will not be deallocated. As a corollary, this means that it does not make sense for a timer's target to try to invalidate the timer in its dealloc method"the dealloc method will not be invoked as long as the timer is valid.



     


    Source: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Timers/Articles/usingTimers.html#//apple_ref/doc/uid/20000807-CJBJCBDE


  • FKDEVFKDEV Membre

    Des outils comme Build&Analyze ou l'app fauxpas signalent-ils ce problème ?

  • CéroceCéroce Membre, Modérateur
    ça ne ma parait pas possible de le détecter en analyse statique, puisque le timer a une relation dynamique avec sa cible.
  • MalaMala Membre, Modérateur


    Des outils comme Build&Analyze ou l'app fauxpas signalent-ils ce problème ?




    Ce n'est pas un problème mais un fait fonctionnel. Il n'y a aucun bug derrière si ce n'est la méconnaissance du développeur qui l'emploie.

  • À noter ce pod qui gère un timer alternatif qui ne retain par son target !


     


    https://github.com/mindsnacks/MSWeakTimer


Connectez-vous ou Inscrivez-vous pour répondre.