2009-06-23 24 views
22

Tengo un temporizador que se dispara cuando se llama al método viewWillAppear y se invalida cuando se llama al método viewDidDisappear. Pero después de una cierta cantidad de cambio entre las vistas, el temporizador continúa disparando incluso después de que se haya invalidado. ¿Cuál es el problema?NSTimer no se detiene

Aquí está mi código:

NSTimer *timer; 

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 
    timer = [NSTimer scheduledTimerWithTimeInterval: 0.2f 
        target: self 
        selector:@selector(timerAction) 
        userInfo:nil 
        repeats:YES]; 
} 

-(void)viewDidDisappear:(BOOL)animated { 
    [super viewDidDisappear:animated]; 
    [timer invalidate]; 
    timer = nil; 
} 

-(void) timerAction 
{ 
    NSLog(@"timerAction"); 
} 

Respuesta

37

Debí mantener un enlace al temporizador reteniéndolo. :) Hace 5 meses hice esta pregunta, y es increíble, cuanto más experiencia adquirí. :)

timer = [ [NSTimer scheduledTimerWithTimeInterval: ...] retain]; 
... 
... 
[timer invalidate]; 
[timer release]; 
+0

Cómo hacer esto en ARC cuando '' retain' y puesta en circulación no están permitidos? –

+1

Para iOS 7/8, ver la respuesta por debajo de aproximadamente utilizando un par de 'repite: temporizadores NO'. –

0

Se ha olvidado para liberar el contador de tiempo en viewWillDisappear:

- (void)viewDidDisappear:(BOOL)animated 
{ 
    [super viewDidDisappear:animated]; 
    [timer invalidate]; 
    [timer release]; 
    timer = nil; 
} 

Esto no debe hacer que el contador de tiempo para seguir disparando aunque ...

+1

en este caso de aplicaciones aplasta porque temporizador ya está siendo puesto en libertad. –

+0

Ben Gotow tiene la respuesta correcta aquí. Debe conservar el temporizador después de haberlo creado y luego invalidarlo y soltarlo cuando desee que deje de devolverle la llamada – rpetrich

+0

No lo tiene/lo tiene/para retenerlo, ya que el ciclo de ejecución lo hará, pero es una buena idea si quieres estar a salvo – Wevah

0

De invalidatedoco dice

"El ciclo de ejecución elimina y libera el temporizador, ya sea justo antes de que regrese el método de invalidación o en algún momento posterior".

Supongo que el suyo se eliminará en algún momento posterior.

6

Un método llamado por un temporizador debe tener la definición

- (void)methodName:(NSTimer *)aTimer; 

De esta manera el método tiene la instancia de temporizador que fue despedido. La forma en que lo está haciendo, el método no sabrá si el temporizador fue invalidado o no.

trate de cambiar su inicialización temporizador para

timer = [NSTimer scheduledTimerWithTimeInterval: 0.2f target: self selector:@selector(timerAction:) userInfo:nil repeats:YES] 

y el método de

-(void) timerAction:(NSTimer *)aTimer{...} 

Espero que ayude

+0

Esto no tendrá ningún efecto. – rpetrich

+0

@rpetrich Si usted puede dar aún menos información en su respuesta que sería un gran tipo! –

+1

Invalidar el objeto de temporizador en el método y que sea un nulo. También asegúrese de que el NSTimer se declare como una propiedad de retención. Esto funciona para mí –

2

esto puede no ser el problema, pero hay que mantener la referencia a temporizador que se devuelve desde scheduledTimerWithInterval :. Sin hacer esto, su puntero al temporizador podría no ser válido cuando vaya a detenerlo.

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 
    timer = [[NSTimer scheduledTimerWithTimeInterval:0.2f target:self selector:@selector(timerAction) userInfo:nil repeats:YES] retain]; 
} 

- (void)viewDidDisappear:(BOOL)animated 
{ 
    [timer invalidate]; 
    [timer release]; 
    timer = nil; 
    [super viewDidDisappear:animated]; 
} 

- (void)dealloc 
{ 
    [timer invalidate]; 
    [timer release]; 
    timer = nil; 
    [super dealloc]; 
} 

Además, intente establecer un punto de interrupción en viewDidDisappear y asegúrese de que se llame.

0

Tuve el mismo problema.

No puedo dealloc mi ejemplo, si el temporizador sigue en funcionamiento, así que tengo que detenerlo antes de llamar:

- (void)stopTimer 
{ 
    [timer invalidate]; 
    [timer release]; 
    timer = nil; 
} 

Después de llamar a este método realmente mi temporizador se detiene

1
**In .h class** 

@interface 
{ 
NSTimer * theTimer; 

} 


**in .m class** 

//put this code where you want to calling the NSTimer function 

     theTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateCounter:) userInfo:nil repeats:YES]; 



- (void)updateCounter:(NSTimer *)theTimer 
{ 

    // write your code here for counter update 

} 


// put this code to Stop timer: 

    [theTimer invalidate]; 
    theTimer = nil; 
14

Este es una solución absolutaNinguno de los de arriba que funcionó para mí, así que me hizo esto,

en la que desea iniciar el temporizador,

[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:NO]; 

El método que las llamadas de temporizador,

-(void)timerMethod 
{ 
    // do what you need to do 

    if (needs to be called again) { 

     [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:NO];   
    } 
} 

espero que esto ayude ,

+2

Eso es lo único que funciona para mí también ... – Idan

+2

De hecho ... Parece un error de Apple para mí. El método de invalidación no funciona porque el valor de BOOL repetido establecido en SÍ me resulta un poco extraño – Plot

+2

Este error todavía existe en iOS8. Esta es la única manera posible de resolver el problema. – Anil

0

- (void)viewWillAppear:(BOOL)animated se llama nuevamente.

De hecho, recibe una llamada cada vez que cambia de vista o después de cerrar una vista modal. Básicamente cada vez que su vista reaparece en la pantalla, no solo la primera vez.

Por lo tanto, en este caso, el temporizador se reinicia, aunque ya se haya invalidado antes.

0

Después de crear el temporizador registrate que se ejecute en NSRunLoopCommonModes:

[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];

Entonces invalidate método funcionará.

0

Esto funciona para mí

dispatch_async(dispatch_get_main_queue(), ^{ 
    [timer invalidate]; 
}); 
1

Esto hizo el truco para mí en Swift

override func viewWillDisappear(animated: Bool) { 
    super.viewWillDisappear(animated) 

    dispatch_async(dispatch_get_main_queue(),{ [weak self] in 

     self?.idleTimer?.invalidate() 
     self?.idleTimer = nil 

    }) 

} 
Cuestiones relacionadas