Reputation: 2099
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
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
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
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
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