Here\'s my issue:
I have a model class that has an NSTimer
in it that I want the Timer to run for the entire lifespan of the model object. Initiliazati
Based on @Martin R idea, I create custom class which easier to use, and add some checking to avoid crash.
@interface EATimerTarget : NSObject
// Initialize with block to avoid missing call back
- (instancetype)initWithRealTarget:(id)realTarget timerBlock:(void(^)(NSTimer *))block;
// For NSTimer @selector() parameter
- (void)timerFired:(NSTimer *)timer;
@end
@interface EATimerTarget ()
@property (weak, nonatomic) id realTarget;
@property (nonatomic, copy) void (^timerBlock)(NSTimer *); // use 'copy' to avoid retain counting
@end
@implementation EATimerTarget
- (instancetype)initWithRealTarget:(id)realTarget timerBlock:(void (^)(NSTimer *))block {
self = [super init];
if (self) {
self.realTarget = realTarget;
self.timerBlock = block;
}
return self;
}
- (void)timerFired:(NSTimer *)timer {
// Avoid memory leak, timer still run while our real target is dealloc
if (self.realTarget) {
self.timerBlock(timer);
}
else {
[timer invalidate];
}
}
@end
Here is my sample class
@interface MyClass
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation MyClass
- (id)init
{
self = [super init];
if (self) {
// Using __weak for avoiding retain cycles
__weak typeof(self) wSelf = self;
EATimerTarget *timerTarget = [[EATimerTarget alloc] initWithRealTarget:self timerBlock: ^(NSTimer *timer) {
[wSelf onTimerTick:timer];
}];
self.timer = [NSTimer timerWithTimeInterval:1 target:timerTarget selector:@selector(timerFired:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
}
return self;
}
- (void)dealloc
{
[self.timer invalidate]; // This releases the EATimerTarget as well!
NSLog(@"### MyClass dealloc");
}
- (void)onTimerTick:(NSTimer *)timer {
// DO YOUR STUFF!
NSLog(@"### TIMER TICK");
}
@end