更新:我之前那個定時器不知道有沒有人再用,今天發現之前寫的有點問題,定時器停止不了,原因是吧定時器加到子線程里,移除是在主線程運行的移除。正確的是在加入定時器的線程中移除定時器,不然不能正常停止。代碼是沒更新過得,大家注意就好了。
場景:最近做的一個電商項目,很多很多倒計時,,
當我寫到第二個的時候覺得還是把定時的邏輯拿出來寫比較好,想了幾個方法最后決定用觀察者
這么用的原因:比如一個發送驗證碼的按鍵想倒數計時,其實這個按鍵就是想得到一秒一次的一個提醒,讓它來刷新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];
小白勿噴噗