NSTimer拓展

定时器(NSTimer)在我们日常开发中是一个非常有用的系统函数,开发者可以在指定的时间,或延迟执行某些任务,也可以设定间隔时间重复执行任务。

//iOS提供的Timer构造方法
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti 
                            target:(id)aTarget 
                            selector:(SEL)aSelector 
                            userInfo:(nullable id)userInfo 
                            repeats:(BOOL)yesOrNo;

//对应的析构方法
- (void)invalidate;

在使用Timer时,timer会保留target对象,直到自身失效(invalid)后再释放该对象。对于一次性的timer在触发后就会失效,然后重复性的需要手动invalidate,所以alloc和dealloc最好成对出现,才可以防止引起retain,从而造成内存的泄露。


这里通过扩展NSTimer,使用block来消除retain-cycle(如果忘记invalidate,也没有关系了)。

//NSTimer+BlockSupport.h
#import <Foundation/Foundation.h>

@interface NSTimer(BlockSupport)

+ (NSTimer *)law_scheduleTimerWithTimeInterval:(NSTimeInterval)interval
                                       repeats:(BOOL)repeats
                                         block:(void(^)(NSTimer *timer))block;

@end


//NSTimer+BlockSupport.m
#import "NSTimer+BlockSupport.h"

@implementation NSTimer(BlockSupport)

//将block作为userInfo传递进去,并copy到堆栈中,以防止执行block时失效
//这时target是NSTimer本身,NSTimer是一个单例对象,尽管存在ratain cycle,但是没有关系
+ (NSTimer *)law_scheduleTimerWithTimeInterval:(NSTimeInterval)interval
                                     repeats:(BOOL)repeats
                                       block:(void(^)(NSTimer *timer))block {
    return [self scheduledTimerWithTimeInterval:interval
                                         target:self
                                       selector:@selector(law_blockInvoke:)
                                       userInfo:[block copy]
                                        repeats:repeats];
}

+ (void)law_blockInvoke:(NSTimer *)timer {
    void (^block)(NSTimer *timer) = timer.userInfo;
    if (block) {
        block(timer);
    }
}

@end

使用

- (void)startTimer {
    __weak __typeof(self)weakSelf = self;
    [NSTimer law_scheduleTimerWithTimeInterval:5.0 repeats:YES block:^(NSTimer *timer) {
        __strong __typeof(weakSelf)strongSelf = weakSelf;
        [strongSelf doSomething];
    }];
}

- (void)doSomething {
    //do something
}

好消息是,iOS10之后系统已经支持该方法了。不过目前iOS应用大都还需要支持iOS8.0+,所以该拓展还是有那么些作用。

原文地址:https://www.cnblogs.com/horo/p/6854815.html