更新:我之前那個(gè)定時(shí)器不知道有沒有人再用,今天發(fā)現(xiàn)之前寫的有點(diǎn)問題翅萤,定時(shí)器停止不了套么,原因是吧定時(shí)器加到子線程里,移除是在主線程運(yùn)行的移除胚泌。正確的是在加入定時(shí)器的線程中移除定時(shí)器,不然不能正常停止零蓉。代碼是沒更新過得敌蜂,大家注意就好了津肛。
場(chǎng)景:最近做的一個(gè)電商項(xiàng)目,很多很多倒計(jì)時(shí)囊陡,掀亥,
當(dāng)我寫到第二個(gè)的時(shí)候覺得還是把定時(shí)的邏輯拿出來寫比較好妥色,想了幾個(gè)方法最后決定用觀察者
這么用的原因:比如一個(gè)發(fā)送驗(yàn)證碼的按鍵想倒數(shù)計(jì)時(shí)嘹害,其實(shí)這個(gè)按鍵就是想得到一秒一次的一個(gè)提醒,讓它來刷新UI(當(dāng)然能把我計(jì)數(shù)的秒數(shù)返回來更好--雖然這會(huì)讓給它發(fā)通知的人責(zé)任更細(xì)化)幢踏。這樣看來這個(gè)場(chǎng)景就非常符合使用觀察者了--“觀察者模式定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象房蝉。這個(gè)主題對(duì)象在狀態(tài)發(fā)生變化時(shí)微渠,會(huì)通知所有觀察者對(duì)象,使它們能夠自動(dòng)更新自己”檀蹋。
步驟一---協(xié)議
/**
使用者要實(shí)現(xiàn)的協(xié)議
*/
@protocol TimerUserInterface <NSObject>
@property (nonatomic, assign) int allSeconds;//倒計(jì)時(shí)開始時(shí)的秒數(shù)
-(void)receivedTimerUpData:(NSString *)timeString;
@end
/**
定時(shí)器要使用的協(xié)議
*/
@protocol TimerNotifierInterface <NSObject>
-(BOOL)registUser:(id<TimerUserInterface>)timerUser;
-(BOOL)removeUser:(id<TimerUserInterface>)timerUser;
-(void)notifierAllUser;
@end
步驟二---定時(shí)器實(shí)現(xiàn)
定時(shí)器的實(shí)現(xiàn)我用了單例模式保證我只是維護(hù)者一個(gè)定時(shí)器在運(yùn)行這樣在一個(gè)頁(yè)面里有多個(gè)要定時(shí)器的時(shí)候保證消耗小計(jì)時(shí)同步準(zhǔn)確
#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) {//倒計(jì)時(shí)結(jié)束后自動(dòng)移除用戶
[self removeUser:obj];
}
NSString *timeStr = [self getHourMinutesAndSeconds:obj.allSeconds];
[obj receivedTimerUpData:timeStr];
}];
}
@end
步驟三---使用
使用時(shí)有一個(gè)地方注意因?yàn)槲覀兊膮f(xié)議里帶有一個(gè)屬性所以要用@synthesize allSeconds;聲明下(set get 方法)
self.allSeconds = 120;
id<TimerNotifierInterface> notiier = (id<TimerNotifierInterface>)[TimerNotifier standard];
[notiier registUser:self];
//記得不用的時(shí)候移除掉
id<TimerNotifierInterface> notiier = (id<TimerNotifierInterface>)[TimerNotifier standard];
[notiier removeUser:self];
小白勿噴噗