本文将参考微信和微博,猜想其实现,并探究如何处理点赞功能。数据库
微信朋友圈的点赞数相对来讲少。微博的点赞数能达五位数。其应该采用了不一样的策略。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内无再次点击,而且和原状态不同,才发起网络请求。在视图退出界面的时候也立刻发起网络请求。
想得还不是很完善,但愿能抛砖引玉。