定时器(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+,所以该拓展还是有那么些作用。