What is the correct way to release a NSTimer in my dealloc method ? It was created with the following code ?
-(void)mainTimerLoop {
mainTimer = [NSTimer scheduledTimerWithTimeInterval:1/10
target:self
selector:@selector(gameLoop)
userInfo:nil
repeats:YES];
}
Thanks
The way you're doing it, you won't ever hit dealloc
. A timer retains its target. In this case, that means the timer has retained you. It will not release you until it is invalidated. Since you created the timer, you must also invalidate it at some point prior to dealloc
, because the timer's retain will prevent your object's being dealloc
ed.
You have two options:
As an example of the latter:
@interface GameLoopTimerTarget : NSObject {
id owner; /* not retained! */
}
- (id)initWithOwner:(id)owner;
- (void)timerDidFire:(NSTimer *)t;
@end
@implementation GameLoopTimerTarget
- (id)initWithOwner:(id)owner_ {
self = [super init];
if (!self) return nil;
owner = owner_;
return self;
}
- (void)timerDidFire:(NSTimer *)t {
#pragma unused (t)
[owner performSelector:@selector(gameLoop)];
}
@end
/* In your main object… */
/* assume synthesized:
@property (retain, NS_NONATOMIC_IPHONE_ONLY) GameLoopTimer *mainTimerTarget; */
- (void)mainTimerLoop {
self.mainTimerTarget = [[[GameLoopTimerTarget alloc] initWithOwner:self] autorelease];
mainTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0 target:self.mainTimerTarget selector:@selector(timerDidFire:) userInfo:nil repeats:YES];
}
- (void)dealloc {
/* other stuff */
[timer invalidate], timer = nil;
[mainTimerTarget release], mainTimerTarget = nil;
/* more stuff */
[super dealloc];
}
Notice how the time interval is 1.0/10.0
- this could also be written 0.1
, but it cannot be written 1/10
, as that division will truncate to 0.0
.
Also notice how this breaks the retain cycle:
A valid NSTimer is retained by the run loop, which, if it is repeating, will be forever or until you invalidate it. You shouldn't release it, since, in your example code, you did not explicitly retain it. If you invalidate it, it will no longer be retained by the run loop, and will be autoreleased.
This might be OK for a repeating timer, but is dangerous for a one-shot timer, since it might end being released before you ever access it to see if it's valid and/or try to invalidate it (which would lead to a bad-access app crash). Therefore if you plan on, in any way, looking at a timer variable after it's creation (including to check it, invalidate it and/or release it), it might be a good practice to explicitly retain it somewhere in your app, and then release it and set it to nil after it's invalid and you are done with it.
You can release it and set it to nil in one statement if you declare it as a retain property. Then you can write:
self.timer = nil;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With