33 votes

Meilleur moment pour invalider NSTimer dans UIViewController pour éviter de conserver le cycle

Croit-on savoir quand est le meilleur moment pour arrêter une NSTimer qui est tenu de référence à l'intérieur d'un UIViewController pour éviter de conserver cycle entre le minuteur et le contrôleur?

Voici la question plus en détails: j'ai un NSTimer à l'intérieur d'un UIViewController.

Au cours de ViewDidLoad de la vue-contrôleur, j'ai démarrer la minuterie:

statusTimer = [NSTimer scheduledTimerWithTimeInterval: 1 target: self selector: @selector(updateStatus) userInfo: nil repeats: YES];

Ci-dessus les causes de la minuterie pour contenir une référence à la vue du contrôleur.

Maintenant, je veux sortir de mon controller (contrôleur de parent qu'il se dégage par exemple)

la question est: où puis-je mettre de l'appel à [statusTimer invalider] pour forcer la minuterie pour libérer la référence à la manette?

J'ai essayé de mettre dans ViewDidUnload, mais cela ne veut pas tiré jusqu'à ce que l'affichage reçoit un avertissement de mémoire, donc pas un bon endroit. J'ai essayé dealloc, mais dealloc ne sera jamais appelé aussi longtemps que la minuterie est en vie (poulet et de l'oeuf problème).

Toutes les bonnes suggestions?

21voto

Jeremy W. Sherman Points 22019
  1. Vous pourriez éviter de le conserver cycle pour commencer avec, par ex., en vue de la minuterie à une StatusUpdate objet qui est titulaire d'un non-retenu (faible) de référence à votre contrôleur, ou par le fait d'avoir un StatusUpdater qui est initialisé avec un pointeur de votre contrôleur, détient une référence faible pour que, et met en place une minuterie pour vous.

    • Vous pourriez avoir l'affichage l'arrêt de la minuterie en -willMoveToWindow: lorsque la fenêtre cible est nil (qui doit gérer le contre-exemple d' -viewDidDisappear: que vous avez fournis) ainsi que dans -viewDidDisappear:. Cela signifie que votre point de vue est d'atteindre dans votre contrôleur, vous pourriez éviter d'arriver à en saisir la minuterie par suffit d'envoyer au contrôleur une -view:willMoveToWindow: message ou par la publication d'une notification, si vous vous souciez.

    • Sans doute, vous êtes à l'origine de la vue à être retiré de la fenêtre, de sorte que vous pourriez ajouter une ligne à l'arrêt de la minuterie à côté de la ligne qui expulse de la vue.

    • Vous pourriez utiliser un non-répétition de minuterie. Elle invalide dès qu'il se déclenche. Vous pourrez alors tester dans le rappel si un nouveau non-répétition de minuterie doit être créé, et, dans l'affirmative, de le créer. Les indésirables conserver cycle sera alors de ne garder que la minuterie et le contrôleur de la paire de tour jusqu'à ce que le prochain feu de date. Avec 1 seconde d'incendie date, vous n'auriez pas beaucoup à s'inquiéter.

Chaque suggestion, mais le premier est un moyen de vivre avec le cycle de conserver et de le briser au moment opportun. La première suggestion effectivement évite de le conserver cycle.

6voto

Petrakeas Points 101

Une solution consiste à faire en sorte que le NStimer conserve une référence faible à votre UIViewController. J'ai créé une classe qui contient une référence faible à votre objet et transmet les appels à cela:

 #import <Foundation/Foundation.h>

@interface WeakRefClass : NSObject

+ (id) getWeakReferenceOf: (id) source;

- (void)forwardInvocation:(NSInvocation *)anInvocation;

@property(nonatomic,assign) id source;

@end

@implementation WeakRefClass

@synthesize source;

- (id)init{
    self = [super init];
//    if (self) {
//    }
    return self;
}

+ (id) getWeakReferenceOf: (id) _source{

    WeakRefClass* ref = [[WeakRefClass alloc]init];
    ref.source = _source; //hold weak reference to original class

    return [ref autorelease];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [[self.source class ] instanceMethodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    [anInvocation    invokeWithTarget:self.source ];

}

@end
 

et vous l'utilisez comme ceci:

 statusTimer = [NSTimer scheduledTimerWithTimeInterval: 1 target: [WeakRefClass getWeakReferenceOf:self] selector: @selector(updateStatus) userInfo: nil repeats: YES];
 

Votre méthode dealloc est appelée (contrairement à avant) et à l'intérieur vous appelez simplement:

 [statusTimer invalidate];
 

3voto

vodkhang Points 11222

Vous pouvez essayer avec - (void)viewDidDisappear:(BOOL)animated , puis vous devriez le valider à nouveau dans - (void)viewDidAppear:(BOOL)animated

Plus ici

1voto

Josh Lindsey Points 2298

La méthode -viewDidDisappear peut être ce que vous recherchez. Il est appelé chaque fois que la vue est masquée ou supprimée.

1voto

Michal Gumny Points 618

invalider la minuterie à l'intérieur - (void) viewWillDisappear: (BOOL) animé a fonctionné pour moi

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X