更新:我之前那个定时器不知道有没有人再用,今天发现之前写的有点问题,定时器停止不了,原因是吧定时器加到子线程里,移除是在主线程运行的移除。正确的是在加入定时器的线程中移除定时器,不然不能正常停止。代码是没更新过得,大家注意就好了。
场景:最近做的一个电商项目,很多很多倒计时,,
当我写到第二个的时候觉得还是把定时的逻辑拿出来写比较好,想了几个方法最后决定用观察者
这么用的原因:比如一个发送验证码的按键想倒数计时,其实这个按键就是想得到一秒一次的一个提醒,让它来刷新UI(当然能把我计数的秒数返回来更好--虽然这会让给它发通知的人责任更细化)。这样看来这个场景就非常符合使用观察者了--“观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己”。
步骤一---协议
/**
使用者要实现的协议
*/
@protocol TimerUserInterface <NSObject>
@property (nonatomic, assign) int allSeconds;//倒计时开始时的秒数
-(void)receivedTimerUpData:(NSString *)timeString;
@end
/**
定时器要使用的协议
*/
@protocol TimerNotifierInterface <NSObject>
-(BOOL)registUser:(id<TimerUserInterface>)timerUser;
-(BOOL)removeUser:(id<TimerUserInterface>)timerUser;
-(void)notifierAllUser;
@end
步骤二---定时器实现
定时器的实现我用了单例模式保证我只是维护者一个定时器在运行这样在一个页面里有多个要定时器的时候保证消耗小计时同步准确
#import "TimerNotifier.h"
@interface TimerNotifier ()<TimerNotifierInterface>
@property (nonatomic, strong) NSTimer * timer;
@property (nonatomic, strong) NSMutableArray<id<TimerUserInterface>> *timerUsers;
@end
@implementation TimerNotifier
#pragma mark - Init
+(instancetype)standard{
static TimerNotifier *timerNotifierTool = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
timerNotifierTool = [[TimerNotifier alloc] init];
});
return timerNotifierTool;
}
-(NSMutableArray *)timerUsers{
if (nil == _timerUsers) {
_timerUsers = [[NSMutableArray alloc]init];
}
return _timerUsers;
}
-(NSTimer *)timer{
if (nil == _timer) {
_timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerDownEvent) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
}
return _timer;
}
#pragma mark - Event
-(void)timerDownEvent{
[self notifierAllUser];
}
-(NSString *)getHourMinutesAndSeconds:(int)totalSeconds{
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
return [NSString stringWithFormat:@"%02d%02d%02d",hours, minutes, seconds];
}
#pragma mark - TimerNotifierInterface
-(BOOL)registUser:(id<TimerUserInterface>)timerUser{
[self.timerUsers addObject:timerUser];
if (self.timerUsers.count <= 0) {
return NO;
}
if (self.timerUsers.count == 1) {
[self.timer fire];
}
return YES;
}
-(BOOL)removeUser:(id<TimerUserInterface>)timerUser{
[self.timerUsers removeObject:timerUser];
if (self.timerUsers.count == 0) {
[self.timer timeInterval];
self.timer = nil;
}
return YES;
}
-(void)notifierAllUser{
[self.timerUsers enumerateObjectsUsingBlock:^(id<TimerUserInterface> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
obj.allSeconds--;
if (obj.allSeconds == 0) {//倒计时结束后自动移除用户
[self removeUser:obj];
}
NSString *timeStr = [self getHourMinutesAndSeconds:obj.allSeconds];
[obj receivedTimerUpData:timeStr];
}];
}
@end
步骤三---使用
使用时有一个地方注意因为我们的协议里带有一个属性所以要用@synthesize allSeconds;声明下(set get 方法)
self.allSeconds = 120;
id<TimerNotifierInterface> notiier = (id<TimerNotifierInterface>)[TimerNotifier standard];
[notiier registUser:self];
//记得不用的时候移除掉
id<TimerNotifierInterface> notiier = (id<TimerNotifierInterface>)[TimerNotifier standard];
[notiier removeUser:self];
小白勿喷噗