How to know when to invalidate an `NSTimer`

前端 未结 2 1841
无人共我
无人共我 2020-12-16 05:22

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

2条回答
  •  天涯浪人
    2020-12-16 05:42

    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
    

提交回复
热议问题