iOS検証コードのカウントダウンを実現し、終了してからカウントダウンを継続する
12275 ワード
需要
Appには認証コードを送信するページがたくさんありますが、認証コードにかかわる場所にはカウントダウン機能があるに違いありません.製品は検証コードの送信を要求した後、カウントダウンが終了するまで検証コードを繰り返し送信しない.
最初のステップ
まずカウントダウン機能を実現し、ログイン画面を例にとると、ユーザーが携帯電話番号を入力した後、ボタンをクリックして検証コードを送信する必要があり、検証コードを送信することに成功した後、以下の方法を呼び出し、ボタンカウントダウン機能を実現する.
- (void)timerCountDownWithType:(BOUCountDownType)countDownType {
_countDonwnType = countDownType;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), 1.0 * NSEC_PER_SEC, 0);
NSTimeInterval seconds = kMaxCountDownTime;
NSDate *endTime = [NSDate dateWithTimeIntervalSinceNow:seconds];
dispatch_source_set_event_handler(_timer, ^{
int interval = [endTime timeIntervalSinceNow];
if (interval <= 0) {
dispatch_source_cancel(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
// , ,
[self.meeageButton setTitle:@" " forState:UIControlStateNormal];
[self.meeageButton setEnabled:YES];
});
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
// interval ,
[self.meeageButton setTitle:@(interval).stringValue forState:UIControlStateNormal];
[self.meeageButton setEnabled:NO];
});
}
});
dispatch_resume(_timer);
}
上記の方法ではボタンのカウントダウン機能が実現されていますが、戻るボタンをクリックせずに現在のページを離れるとカウントダウンは正常ですが、
, ,
です.ユーザーは認証コードを再送信できますが、前回のカウントダウン時間はまだ来ていません.この
なので、上記のスキームは調整する必要があります.ステップ2
考えた結果,カウントダウン機能を1つのクラスに個別にカプセル化し,重複コードの頻繁な書き込みを避けることにした.
1.
BOUTimerManager
クラスを新設し、NSObject
から継承する複数のページでカウントダウン機能が必要なため、カウントダウンが属するページを区別するには、次の列挙タイプを定義します.
typedef NS_ENUM(NSInteger, BOUCountDownType) {
BOUCountDownTypeLogin,//
BOUCountDownTypeFindPassword,//
BOUCountDownTypeRegister,//
BOUCountDownTypeModifyPhone,//
};
BOUTimerManager.h
ファイルで次の方法を定義します.+ (instancetype)shareInstance;//
- (void)timerCountDownWithType:(BOUCountDownType)countDownType;// , type 。
- (void)cancelTimerWithType:(BOUCountDownType)countDownType;// , type 。
カウントダウンプロセスでは、応答インタフェースはカウントダウン中またはカウントダウン完了処理に関するページロジックに基づいている必要があります.ここでは通知を送信する方法を使用して、カウントダウンプロセスとカウントダウン完了時に通知を送信します.ページ登録通知後、カウントダウン状態を受信することができます.
BOUTimerManager.h
では、以下の内容を定義する必要があります.#define kLoginCountDownCompletedNotification @"kLoginCountDownCompletedNotification"
#define kFindPasswordCountDownCompletedNotification @"kFindPasswordCountDownCompletedNotification"
#define kRegisterCountDownCompletedNotification @"kRegisterCountDownCompletedNotification"
#define kModifyPhoneCountDownCompletedNotification @"kModifyPhoneCountDownCompletedNotification"
#define kLoginCountDownExecutingNotification @"kLoginCountDownExecutingNotification"
#define kFindPasswordCountDownExecutingNotification @"kFindPasswordCountDownExecutingNotification"
#define kRegisterCountDownExecutingNotification @"kRegisterCountDownExecutingNotification"
#define kModifyPhoneCountDownExecutingNotification @"kModifyPhoneCountDownExecutingNotification"
BOUTimerManager.h
のすべての内容は以下の通りです.#import
#define kLoginCountDownCompletedNotification @"kLoginCountDownCompletedNotification"
#define kFindPasswordCountDownCompletedNotification @"kFindPasswordCountDownCompletedNotification"
#define kRegisterCountDownCompletedNotification @"kRegisterCountDownCompletedNotification"
#define kModifyPhoneCountDownCompletedNotification @"kModifyPhoneCountDownCompletedNotification"
#define kLoginCountDownExecutingNotification @"kLoginCountDownExecutingNotification"
#define kFindPasswordCountDownExecutingNotification @"kFindPasswordCountDownExecutingNotification"
#define kRegisterCountDownExecutingNotification @"kRegisterCountDownExecutingNotification"
#define kModifyPhoneCountDownExecutingNotification @"kModifyPhoneCountDownExecutingNotification"
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, BOUCountDownType) {
BOUCountDownTypeLogin,
BOUCountDownTypeFindPassword,
BOUCountDownTypeRegister,
BOUCountDownTypeModifyPhone,
};
@interface BOUTimerManager : NSObject
DEF_SINGLETON(BOUTimerManager);
- (void)timerCountDownWithType:(BOUCountDownType)countDownType;
- (void)cancelTimerWithType:(BOUCountDownType)countDownType;
@end
NS_ASSUME_NONNULL_END
BOUTimerManager.m
の実装内容は以下の通りである.#import "BOUTimerManager.h"
#define kMaxCountDownTime 60// ,
@interface BOUTimerManager ()
@property (nonatomic, assign) BOUCountDownType countDonwnType;
@property (nonatomic, nullable, strong) dispatch_source_t loginTimer;// timer
@property (nonatomic, nullable, strong) dispatch_source_t findPwdTimer;// timer
@property (nonatomic, nullable, strong) dispatch_source_t registerTimer;// timer
@property (nonatomic, nullable, strong) dispatch_source_t modifyPhoneTimer;// timer
@end
@implementation BOUTimerManager
IMP_SINGLETON(BOUTimerManager);
- (void)timerCountDownWithType:(BOUCountDownType)countDownType {
_countDonwnType = countDownType;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), 1.0 * NSEC_PER_SEC, 0);
NSTimeInterval seconds = kMaxCountDownTime;
NSDate *endTime = [NSDate dateWithTimeIntervalSinceNow:seconds];
dispatch_source_set_event_handler(_timer, ^{
int interval = [endTime timeIntervalSinceNow];
if (interval <= 0) {
dispatch_source_cancel(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
if ([_timer isEqual:self.loginTimer]) {
[[NSNotificationCenter defaultCenter] postNotificationName:kLoginCountDownCompletedNotification object:@(interval)];
} else if ([_timer isEqual:self.findPwdTimer]) {
[[NSNotificationCenter defaultCenter] postNotificationName:kFindPasswordCountDownCompletedNotification object:@(interval)];
} else if ([_timer isEqual:self.registerTimer]) {
[[NSNotificationCenter defaultCenter] postNotificationName:kRegisterCountDownCompletedNotification object:@(interval)];
} else if ([_timer isEqual:self.modifyPhoneTimer]) {
[[NSNotificationCenter defaultCenter] postNotificationName:kModifyPhoneCountDownCompletedNotification object:@(interval)];
}
});
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
if ([_timer isEqual:self.loginTimer]) {
[[NSNotificationCenter defaultCenter] postNotificationName:kLoginCountDownExecutingNotification object:@(interval)];
} else if ([_timer isEqual:self.findPwdTimer]) {
[[NSNotificationCenter defaultCenter] postNotificationName:kFindPasswordCountDownExecutingNotification object:@(interval)];
} else if ([_timer isEqual:self.registerTimer]) {
[[NSNotificationCenter defaultCenter] postNotificationName:kRegisterCountDownExecutingNotification object:@(interval)];
} else if ([_timer isEqual:self.modifyPhoneTimer]) {
[[NSNotificationCenter defaultCenter] postNotificationName:kModifyPhoneCountDownExecutingNotification object:@(interval)];
}
});
}
});
if (self.countDonwnType == BOUCountDownTypeLogin) {
self.loginTimer = _timer;
} else if (self.countDonwnType == BOUCountDownTypeFindPassword) {
self.findPwdTimer = _timer;
} else if (self.countDonwnType == BOUCountDownTypeRegister) {
self.registerTimer = _timer;
} else if (self.countDonwnType == BOUCountDownTypeModifyPhone) {
self.modifyPhoneTimer = _timer;
}
dispatch_resume(_timer);
}
- (void)cancelTimerWithType:(BOUCountDownType)countDownType {
switch (countDownType) {
case BOUCountDownTypeLogin:
if (self.loginTimer) {
dispatch_source_cancel(self.loginTimer);
}
break;
case BOUCountDownTypeRegister:
if (self.registerTimer) {
dispatch_source_cancel(self.registerTimer);
}
break;
case BOUCountDownTypeModifyPhone:
if (self.modifyPhoneTimer) {
dispatch_source_cancel(self.modifyPhoneTimer);
}
break;
case BOUCountDownTypeFindPassword:
if (self.findPwdTimer) {
dispatch_source_cancel(self.findPwdTimer);
}
break;
default:
break;
}
}
@end
DEF_SINGLETONは、一例宣言のマクロ定義であり、IMP_SINGLETONは、一例で実現されるマクロ定義である
#undef DEF_SINGLETON
#define DEF_SINGLETON( __class ) \
+ (__class *)sharedInstance;
#undef IMP_SINGLETON
#define IMP_SINGLETON( __class ) \
+ (__class *)sharedInstance \
{ \
static dispatch_once_t once; \
static __class * __singleton__; \
dispatch_once( &once, ^{ __singleton__ = [[__class alloc] init]; } ); \
return __singleton__; \
}
2.コントローラでの処理ロジック、ログイン画面を例に
init
メソッドにカウントダウン通知イベントを登録[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginTimerCountDownCompleted) name:kLoginCountDownCompletedNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginTimerCountDownExecutingWithTimeOut:) name:kLoginCountDownExecutingNotification object:nil];
#pragma mark - NSNotification
- (void)loginTimerCountDownExecutingWithTimeOut:(NSNotification *)notification {
NSInteger timeOut = [notification.object integerValue];
NSString *timeStr = [NSString stringWithFormat:@"(%.2ld) ",(long)timeOut];
self.topView.btnCountDown.selected = YES;// self.topView.btnCountDown button
[self.topView.btnCountDown setTitle:timeStr forState:UIControlStateNormal];// self.topView.btnCountDown button
[self.topView.btnCountDown setTitleColor:COLOR_WITH_HEX(0x999999) // self.topView.btnCountDown buttonforState:UIControlStateNormal];
self.topView.btnCountDown.userInteractionEnabled = NO;
}
- (void)loginTimerCountDownCompleted {
self.topView.btnCountDown.selected = NO;// self.topView.btnCountDown button
[self.topView.btnCountDown setTitle:@" " forState:UIControlStateNormal];// self.topView.btnCountDown button
[self.topView.btnCountDown setTitleColor:NavigationColor forState:UIControlStateNormal];// self.topView.btnCountDown button
self.topView.btnCountDown.userInteractionEnabled = YES;// self.topView.btnCountDown button
}
dealloc
メソッドでの登録破棄通知- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
携帯電話番号を入力したら、送信認証コードをクリックし、バックグラウンドインタフェースが成功した後、カウントダウンを開始します.
- (void)sendSMSRequestWithPhone:(NSString *)phoneNum sender:(UIButton *)sender {
//
//...
//
[[BOUTimerManager sharedInstance] timerCountDownWithType:BOUCountDownTypeLogin];
}
ログインボタンをクリックし、バックグラウンドインタフェースが戻ってきたら、ログインインタフェース検証コードカウントダウンをキャンセルします.
- (void)clickLoginAction:(UIButton *)sender {
//
//...
//
[[BOUTimerManager sharedInstance] cancelTimerWithType:BOUCountDownTypeLogin];
}
の最後の部分
以上が実現プロセス全体です