原由
問題的原由很簡單疹味,就是我在使用支付寶花唄功能是,由于網(wǎng)絡(luò)慢的原因重復(fù)點擊了我的賬單和我的額度時盖腕,出現(xiàn)頁面重復(fù)加載的情況钝域。點擊次數(shù)和加載次數(shù)是相同的(我點擊了5次跳了5次),并且是可以穩(wěn)定復(fù)現(xiàn)的妇萄。但是這個小bug蜕企,說實話咬荷,無足輕重,完全不影響使用轻掩,更不會誤導用戶萍丐。
大概是去年11月我是發(fā)現(xiàn)過微信的一個導致app卡死的bug,當時沒有什么頭緒,后來也就放棄思考沒有記錄放典,至今懊惱不已逝变。所以這次本著發(fā)現(xiàn)問題解決問題不逃避的想法,還是把這個寫下來奋构。雖然很easy壳影,但求不被拍磚。
原因
其實問題的原因很容易就猜到弥臼,是在花唄頁面點擊我的賬單是宴咧,app請求數(shù)據(jù),但是由于網(wǎng)絡(luò)的原因径缅,接受數(shù)據(jù)大概延遲了兩秒掺栅。而在這期間我以為有什么問題,所以點擊了五次纳猪。在接受數(shù)據(jù)時氧卧,點擊事件由于沒有檢測的原因而執(zhí)行了5次,于是頁面跳轉(zhuǎn)了5次氏堤。
其實這個問題我自己在開發(fā)過程中也是發(fā)現(xiàn)過好幾次沙绝,比如在亞程旅游iOSapp的自由行城市選擇中,由于數(shù)據(jù)量大且有多個接口鼠锈,會使用戶明顯感覺到延遲闪檬,用戶在animation動畫出現(xiàn)前快速點擊兩次,會有出現(xiàn)重復(fù)跳轉(zhuǎn)的情況购笆。直到這會兒才總結(jié)這個問題粗悯,慚愧。以前我是加個bool值來判斷是否執(zhí)行同欠,我覺得這是很簡潔明了的样傍。但是如果有同樣的情況又將要寫重復(fù)的代碼,所以將這個無論多少次點擊跳轉(zhuǎn)頁面且執(zhí)行一次的功能寫成category行您。
解決方案
方案一外部阻止處理點擊事件
通過bool值來判斷是否執(zhí)行過铭乾。代碼量比較少就貼下了。
@interface UIView (delay)
@property (nonatomic, copy) dispatch_block_t oneTapBlock;
@property (nonatomic, assign) BOOL taskShouldBeCanceled;
@end
@implementation UIView (delay)
- (void)setOneTapBlock:(dispatch_block_t)oneTapBlock{
oneTapBlock();
//**細節(jié)在這里
self.taskShouldBeCanceled = YES;
}
- (dispatch_block_t)oneTapBlock{
return self.oneTapBlock;
}
- (void)setTaskShouldBeCanceled:(BOOL)taskShouldBeCanceled{
//**細節(jié)在這里
objc_setAssociatedObject(self, @"taskShouldBeCanceled", @(!taskShouldBeCanceled), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)taskShouldBeCanceled{
return [objc_getAssociatedObject(self, @"taskShouldBeCanceled") boolValue];
}
@end
#import "BaseViewController.h"
#import "UIView+delay.h"
@interface BaseViewController ()
@property (nonatomic, strong) UIButton *button;
@end
@implementation BaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
_button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 50)];
_button.backgroundColor = [UIColor redColor];
[self.view addSubview:_button];
[_button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];
}
- (void)click {
__weak typeof(self) weakSelf = self;
if (!_button.taskShouldBeCanceled) {
_button.oneTapBlock = ^{
//只需要將點擊事件代碼寫在這里就可以
UIViewController *vc = [[UIViewController alloc] init];
vc.title = [NSString stringWithFormat:@"%@", @(arc4random() % 10)];
[weakSelf.navigationController pushViewController:vc animated:YES];
};
}
}
@end
方案二內(nèi)部阻止處理點擊事件
這個感覺比較困難娃循,因為要在block內(nèi)部檢測自己是否已經(jīng)被執(zhí)行過炕檩,在跳轉(zhuǎn)頁面的這種情況可以通過當前viewcontroller來決定執(zhí)行block內(nèi)的點擊事件。但是如果要在block內(nèi)部來取消自己,感覺這是比較困難的笛质,如果各位大神有什么好的想法懇求不吝賜教泉沾。
引申支付寶單車掃描
在使用的過程中我感覺,支付寶的掃描速度是要略微比微信慢的妇押。一般微信點擊后感覺都沒有開始掃描就已經(jīng)識別二維碼跷究,然后請求數(shù)據(jù)了。而支付寶感覺開始掃描了一秒或者0.5秒這樣才識別二維碼敲霍,然后請求數(shù)據(jù)了俊马。這種毫秒級別的掃描,在平時可能沒有什么太大的影響肩杈,但是在每天早上騎車上班的時候柴我,確實被我放大了很多倍。另外在高頻次的日常掃描支付的時候扩然,我想各位看官也是能夠體會到這種差別的艘儒。不得不承認微信的掃描優(yōu)化獨步江湖。
另外在使用單車的時候夫偶,其實我想問問為什么沒有暫停功能界睁。每次回家的時候會路過一些便利店或者是想要吃飯,但是如果把車放在外面不關(guān)閉兵拢,等我出來的時候車就被人騎走了翻斟。騎走了倒也無所謂,你倒是不騎了就給我關(guān)了啊卵佛。結(jié)果我在第二天早上杨赤,掃描時說我已經(jīng)騎了八百多分鐘敞斋,好像要十幾塊大洋截汪,欲哭無淚。但是我在聯(lián)系客服時植捎,說明異常后沒有扣款衙解,這一點我是比較欣慰的。說到這個焰枢,想起了我一個哥們兒蚓峦,也是類似的情況,但是騎的是mobike結(jié)果更是扣了幾十塊(心疼一秒鐘)济锄。其實單車可以更加人性化的暑椰,比如暫停功能,每天消費上限等等荐绝。
總之一汽,一個服務(wù)更厲害,一個產(chǎn)品更厲害。
我的建議
我有什么建議召夹?當然他們可以認同我提出的bug岩喷,并認同我的解決方案啊。
github源碼
取消用戶點擊事件跨平臺操作方案
由于有兩位觀眾老爺?shù)臒崃矣懻摷嘣鳎o了我一點啟發(fā)纱意。
無論是native還是hybrid在前一頁面請求數(shù)據(jù)后跳轉(zhuǎn)到下一頁面,如果沒有做優(yōu)化鲸阔,在網(wǎng)絡(luò)不佳的情況下就容易出現(xiàn)本文的問題偷霉。
1.如果是H5,可以利用定時器讓函數(shù)延遲執(zhí)行100ms,在100ms內(nèi)如果還出發(fā)了函數(shù)可以刪除上一次調(diào)用褐筛。最關(guān)鍵的就是這一點上了腾它,js里面是可以取消函數(shù)調(diào)用的。
2.ios端死讹,解決方案有很多
2.1在用戶點擊后500ms內(nèi)不允許點擊瞒滴,當點擊事件執(zhí)行時恢復(fù)點擊(外部控制)。
2.2如本文設(shè)置bool值來阻止點擊事件執(zhí)行(外部控制)赞警。
2.3如果是寫在block里面妓忍,而block是無法直接取消的,如果想要在內(nèi)部取消可能需要建立檢測(這一點我現(xiàn)在不知道如何下手愧旦,有大神指教木有)世剖,這樣做比較麻煩。
3.android端笤虫,解決方案類似旁瘫。
(注:最好是將這一功能抽出來,免得到處都是重復(fù)的代碼琼蚯。)