在iOS9或更老系统版本中使用NSTimer+Block方法
在许多倒计时功能(例如获取短信验证码)的时候,我们通常会用以下的方法,
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
这个方法需要设置target和selector,写起来非常不方便而且代码分散到各处,看起来就好丑。
也许苹果大大也觉得这样不好用,于是从iOS10.0开始,NSTimer新增了几个带block的方法,于是乎又感觉到了block的方便与强大。
例如与上述方法具有相同意义的
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
有了它,再写哪些什么button倒计时就简单多了,也更容易阅读,
- (void)startCountDownCode{
__block NSInteger sec=60;
self.codeButton.enabled=NO;
weak_self_define;
[NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
sec=sec-1;
[weakSelf.codeButton setTitle:[NSString stringWithFormat:@"%lds",(long)sec] forState:UIControlStateDisabled];
if (sec<=0) {
weakSelf.codeButton.enabled=YES;
[timer invalidate];
}
}];
}
可是,这里有一个限制,需要iOS10.0及以上才有这个方法,其他系统版本直接崩溃。
那么iOS9和更低的版本就要用回那个老方法吗?那么难用,还丑。坚决不!
我们要想办法让这个方法兼容到iOS9!
得益于强大的Runtime和Category,可以直接给NSTimer加一个block属性,直接动手不墨迹。
我们给项目添加一个文件NSTimer+block.m,覆盖了原有的block方法,使得iOS9以下也可以用。
内容如下:
#import < objc/runtime.h >
@interface NSTimer (BLock)
@property (nonatomic,copy) void(^blockIOS9)(NSTimer* timer);
//这个属性本身是不存在的,需要用runtime添加
@end
@implementation NSTimer (Block)
+(NSTimer*)scheduledTimerWithTimeInterval:(NSTimeInterval)interval
repeats:(BOOL)repeats block:(void (^)(NSTimer *))block
{
NSTimer* timer=[NSTimer scheduledTimerWithTimeInterval:interval
target:self selector:@selector(timerCustomSeletor:)
userInfo:nil repeats:repeats];
//这里的self是指NSTimer的类 ,于是selector也必须是类方法
timer.blockIOS9=block;
return timer;
}
+(void)timerCustomSeletor:(NSTimer*)timer
{
__weak typeof(timer) wetimer=timer; //这里应该可以不用weak修饰
//这里的参数timer是NSTimer的实例,也就是上述类方法返回的timer
if(timer.blockIOS9) //执行block
{
timer.blockIOS9(wetimer);
}
}
-(void)setBlockIOS9:(void (^)(NSTimer *))blockIOS9
{
objc_setAssociatedObject(self, @selector(blockIOS9), blockIOS9, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(void (^)(NSTimer *))blockIOS9
{
return objc_getAssociatedObject(self, @selector(blockIOS9));
}
@end
就这样,使得iOS10才能用的新方法也能在旧版本使用了。
唯一不足之处是,会看见大量的警告,

如果有同学知道消除这些警告的方法,请告诉我,谢谢!