monsabre
monsabre

Reputation: 2099

stop NSTimer causes error

I used the codes below to stop a NSTimer

-(void)stopTimer:(NSTimer*)timer;
{
    if(!timer) return;
    if([timer isValid])
    {

        [timer invalidate];
        timer = nil;

    }



}

sometimes it causes 'EXC Bad Access"

sometimes I got

 -[__NSCFType isValid]: unrecognized selector sent to instance 0x6298eb0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType isValid]: unrecognized selector sent to instance 0x6298eb0'

I think my codes has checked if the NSTimer is valid, if sure then executes 'invalidate'

Welcome any comment

Upvotes: 0

Views: 1228

Answers (4)

conradev
conradev

Reputation: 1074

If at any point the timer invalidates itself (i.e. it doesn't repeat), it is removed and released from the run loop. If you do not retain it yourself, it then becomes deallocated. Calling a method on a deallocated object causes a crash.

To fix this, you can use weak references.

__weak NSTimer *timer;

or

@property (weak, nonatomic) NSTimer *timer;

This makes it so that if at any point the timer becomes deallocated, it is also set to nil.

Upvotes: 0

NJones
NJones

Reputation: 27147

An NSTimer should be an ivar or a property. Retained properties are the easiest since there retains/releases are governed by the @synthesized accessor methods. Since the class now has reference to the NSTimer pointer, there is no need to pass the timer as a parameter. this could be implemented something like this. In .h:

@property (strong, nonatomic) NSTimer *timer;

in .m:

@synthesize timer = _timer;
-(void)stopTimer{
    [self.timer invalidate];
    self.timer = nil;
}
-(void)startTimer{
    [self stopTimer];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(timerTarget) userInfo:nil repeats:YES];
}

The likely reason your method is causing a crash is that you are passing a garbage pointer to it. Either a pointer to a valid object of the wrong class or to a deallocated object whose memory has been reclaimed.

Please not that a pointer to a deallocated object will pass the (!timer) check, unless the pointer (in this case timer) has been set to nil.

Upvotes: 0

DanZimm
DanZimm

Reputation: 2568

If you are invalidating the timer anywhere else then this will occur

Make sure everywhere that the timer is released or invalidated the pointer to it is nil

you could also add a second check of

if ([timer isKindOfClass:[NSTimer class]])

Upvotes: 2

Michael Dautermann
Michael Dautermann

Reputation: 89509

I suspect you are over-releasing your timer variable.

Remove the timer = nil; line and see what happens.

The invalidate documentation says:

This method is the only way to remove a timer from an NSRunLoop object. The NSRunLoop object removes and releases the timer, either just before the invalidate method returns or at some later point.

If it was configured with target and user info objects, the receiver releases its references to those objects as well.

Upvotes: 0

Related Questions