本文將參考微信和微博,猜想其實現,並探究如何處理點贊功能。數據庫
微信朋友圈的點贊數相對來講少。微博的點贊數能達五位數。其應該採用了不一樣的策略。bash
分爲兩類 何時獲取服務器最新點贊數 點贊按鈕與網絡的交互服務器
先研究微博 微信
對於別人的微博。 能夠看到一開始是採用本地存儲的贊數,點進去詳情頁後纔會向網絡獲取一次點贊數,而且更新本地存儲的。(僅發起一次)針對本身發的微博就不研究了,萬年不發一條微博,印象中是收到點贊會收到推送的。網絡
再研究微信併發
打開朋友圈,先用本地的數據,可是當滑動到某一條別人發的朋友圈時。若是有新的贊,會顯示出來(有延遲,應該是網絡請求滯後)。socket
再來看本身發的朋友圈,收到點贊紅點後,滑動下去發現這個贊就躺在那了,無延遲。若是視圖鎖定在本身發的朋友圈內(以下圖),點贊也會更新,由於有收到紅點動態。即收到紅點動態的時候,也會得到點贊信息,有必要的話刷新UI。 別人對本身發的朋友圈首次點贊👇 高併發
對第二點再深刻點。本身發的朋友圈,若是某我的點了贊,查看完紅點後,這我的取消->再次點贊。微信不會顯示紅點。換言之,不屬於新動態。spa
點了別人的贊後,該條朋友圈有新動態也會刷新點贊信息。code
點進詳情頁一定會刷新。
因此大膽猜想,對本身跟蹤的朋友圈,會有個特殊的API獲知哪一條朋友圈的新動態。該API可能採用定時訪問,偶爾就訪問一次;聽杜優秀說多是socket或者protobuf這種高速的http請求。
總結
固然具體的情形遠比這複雜,以上也就是我的瞎猜的。
因爲網絡的不穩定性
以及 用戶可能隨時關閉App致使未成功發出請求
,用戶指望的點贊狀態與數據庫的數據不管如何也不能保證必定一致。
可是如何儘量地實現一致呢?針對這個問題提出我的的愚見。
仍是先從微信和微博入手思考。
無網狀態下
微博UI不變狀態,固然也不發出請求。
微信UI有點贊效果
一開始是沒有點讚的,最終UI設爲點贊。
順便說說結果,連上網後詳情頁發現確實設了點贊。
可是若是關閉微信,再打開,會發現點贊不見了。
不好的網絡狀態下
2G網絡實測,三條微博從無點贊狀態 按了好幾回點贊又取消,退出App連4G後打開看服務器的狀態,發現有些點了贊,有些沒有。即難以肯定。
2G網絡實測,微信點贊後取消點贊,UI忽然變成點贊狀態了。應該是請求成功後刷新本地數據和UI。
如下純屬我的愚見,若是有更好的實現方法,歡迎大佬提出來。
先說個簡單萬能的方法。
有時候,用戶有意識發起的網絡請求,咱們都會顯示「加載中」甚至不讓用戶點擊。而後在請求成功處理數據完成後,再讓用戶點擊。例如登陸界面,點擊登陸後,咱們會顯示"登陸中",而且禁止用戶進行其餘操做。類比着,點贊後,不讓用戶進行其餘操做,顯示「發起請求中」。成功就更換按鈕狀態,失敗提示"點贊失敗/取消點贊失敗"。這樣雖然能徹底避免高併發以及指望值不同但用戶不知道的狀況。
然而,這種方法用戶體驗並很差。可是若是選擇了用戶體驗,帶來的問題是用戶或許無聊會一直點按鈕,高併發請求,對手機內存和服務器都形成了巨大壓力。也有可能最後寫入服務器的數據並非用戶指望值。但主流App都會爲了用戶體驗,承擔這些後果。
因此除了在服務器那加進處理外,手機端也有必要減小高併發的壓力。
在這我更傾向於微信的作法,讓按鈕二級view顯示,這就減小了用戶誤點贊後取消點讚的可能。並且也給了時間完成網絡請求。
還有一種想法是,先讓UI更改,請求失敗就改回去,而且提示「請求失敗」。 微信裏會小紅點提示「點贊未發送」。應該是相似的。
微博那個我並無看懂,有網狀況下,每次點擊都會發起請求,而後隨緣看最後一次的結果嗎?
微信的點贊請求應該是立刻發出的,但取消點贊很難說。由於2G時,點贊後立刻取消點贊,最終結果倒是點贊。
每次點擊都發送是最容易形成高併發和指望值誤差 的操做。 因此不建議每次點擊都發送這種隨緣法。
猜想微信裏應該是更改第一次請求,請求期間點擊按鈕都只是更改個樣子看看,而且請求成功後刷新本地數據和UI。而後才容許下一次請求。
那麼就會有一個問題,微博上剛剛發送點贊請求,而後又點進了詳情頁。因此在點跳轉以前判斷,沒有請求完成就在詳情控制器中註冊了一個通知。當請求成功後,發送通知,通知詳情控制器刷新數據。
猜想代碼以下
NSMutableArray *isRequestingArray;//保存每個cell 是否在發起網絡請求的BOOL
- (void)btnClick:(UIButton *)btn atIndexPath:(NSIndexPath *)indexPath {
// 更改btn的樣子
btn.selected = !btn.selected;
// 還要修改本地的數據 點擊進詳情頁要看到狀態變了
// 最後根據判斷髮起網絡請求
if (![_isRequestingArray[indexPath.section][indexPath.row] boolValue]) { // 無其餘請求
//設置正在請求
_isRequestingArray[indexPath.section][indexPath.row] = @"1";
__weak typeof(self) wself = self;
[PraiseAPI startWithSuccessBlock:^(__kindof BaseRequest *request){
__strong typeof(wself) sself = wself;
sself->isRequestingArray[indexPath.section][indexPath.row] = @"0";
// 更改btn的樣子
// 修改本地的數據
// 發送通知
} failureBlock:^(__kindof BaseRequest *request, NSError *error) {
__strong typeof(wself) sself = wself;
sself->isRequestingArray[indexPath.section][indexPath.row] = @"0";
// 恢復btn的樣子
}];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NextViewcontroller *nextVC = [[NextViewcontroller alloc] init];
if ([_isRequestingArray[indexPath.section][indexPath.row] boolValue]) {
//正在請求 nextVC添加通知
}
[self.navigationController pushViewController:nextVC animated:YES];
}
複製代碼
若點擊後2s內無再次點擊,而且和原狀態不同,才發起網絡請求。在視圖退出界面的時候也立刻發起網絡請求。
想得還不是很完善,但願能拋磚引玉。