仿映客刷礼物效果---代码优化

上一篇文章《仿映客刷礼物效果---基本逻辑实现》中,分析了刷礼物效果的基本流程与具体实现代码。但还有一些BUG和一些可优化的地方没有处理,现在我们就来分析下这些遗留的问题。当然个人的能力是有限的,肯定还有很多我没有发现到的问题,如果大家在使用过程中有遇到其它的问题,欢迎大家及时指出,我好及时完善。

优化后的效果图如下:


效果图.png

废话不多说,先看问题。

问题一

问题描述

问题效果图如下图:


问题一.gif

从图中可以看到:当一个礼物动画组正在执行隐藏动画时,这时恰好收到一个新的与之相同类型的礼物消息,按正常逻辑来看,这个新的礼物消息应该应该作为一个新的动画组开始展示。但是,从GIF图中可以看到,连送按钮再次出现的时,新的动画组并没有开始展示,那新接收到礼物消息去哪里了呢?

问题原因

如果将隐藏动画的动画时间设置长一点,重复上面的问题流程。你就会发现,其实新接收到的礼物消息并不是消失了,而是被判定为一次连乘动画。所以这时其实是一边执行隐藏动画,一遍执行连乘动画,这就导致连乘动画很难被看到,从而造成了新接收到的礼物消息消失了。

问题解决

知道了问题原因,解决问题就非常简单了。这里我的解决方法是:让cell在执行隐藏动画时不被判定为正在执行动画,因此我给cell设置了几种动画状态,其逻辑关系如下图所示:


动画状态逻辑.png

有了动画状态之后,只用修改动画检测的判断条件就可以了,修改后的代码如下:

- (PresentViewCell *)examinePresentingCell:(id<PresentModelAble>)obj
{
    for (PresentViewCell *cell in self.showCells) {
        if ([cell.sender isEqualToString:[obj sender]] && [cell.giftName isEqualToString:[obj giftName]]) {
            //当前正在展示动画并且不是隐藏动画
            if (cell.state != AnimationStateNone && cell.state != AnimationStateHiding) return cell;
        }
    }
    return nil;
}

如果当前没有不为空闲并且也没有在隐藏动画,就判定当前cell可以执行连乘动画。
运行程序,再次测试,就会发现当cell正在执行隐藏动画时收到一条相同类型消息,新的消息会在新的动画组中展示,或是等有了空闲的cell时在展示。(修改后的具体效果可以在Demo中验证,下同)

问题二

问题描述

问题效果图如下:


问题二.gif

从图中可以看到:当连续多次快速的点击同一个发送按钮时,连乘的动画效果就消失了。

问题原因

很明显这里的问题原因就是因为:上一次点击的连乘动画还没执行完,就开始了下一次连乘动画,从而造成了这种效果。

问题解决

从问题原因中很容易想到这里需要用到缓存机制,即等到上一次动画执行完了再执行下一次动画。首先我们很容易想到的就是NSOperationQueue和dispatch_group_t,这是系统封装的两个任务队列,很容易实现上面的需求,而且还特别简单,只用在shakeAnimationWithNumber:里面实现缓存机制就行了。这里介绍下dispatch_group_t队列的实现方法,其代码如下:

- (void)shakeAnimationWithNumber:(NSInteger)number
{
    if (!_queue && !_group) {
        _queue = dispatch_queue_create("com.shakeCache.queue", DISPATCH_QUEUE_SERIAL);
        _group = dispatch_group_create();
        dispatch_group_notify(_group, dispatch_get_main_queue(), ^{
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self hiddenAnimationOfShowShake:YES];
            });
        });
    }
    dispatch_group_async(_group, _queue, ^{
        [self startShakeAnimationWithNumber:number completion:nil];
    });
}

代码很简单,就是创建一个全局的串行队列,如果group任务完成就延时执行隐藏动画,每次调用都想group中添加一个连乘动画任务。
运行程序,你会发现问题还是存在,这是为什么呢?其实原因很简单,就是因为:UIView封装的动画是在子线程中执行,与添加任务操作不在同一个线程中。所以虽然任务是顺序添加的,但动画的执行并不是串行执行的。
这里的解决办法是:自己实现缓存--收到连乘动画先缓存,如果有缓存并且没有正在执行连乘动画,就取缓存,开始动画,动画完成就删除缓存,再去取缓存,只到没有缓存为止。具体实现代码如下:

- (void)shakeAnimationWithNumber:(NSInteger)number
{
    if (number > 0) [self.caches addObject:@(number)];
    if (self.caches.count > 0 && _state != AnimationStateShaking) {
        NSInteger cache        = [self.caches.firstObject integerValue];
        [self.caches removeObjectAtIndex:0];//不能删除对象,因为可能有相同的对象
        __weak typeof(self) ws = self;
        [self startShakeAnimationWithNumber:cache completion:^(BOOL finished) {
            [ws shakeAnimationWithNumber:-1];//传-1是为了缓存不被重复添加
        }];
    }
}

再次运行程序,就会发现连乘动画是串行执行了。

问题三

问题描述

在开始下一次动画去缓存时,这时刚好收到一个与取出的缓存相同类型的消息,又会去取缓存。在极端的情况下,这会造成两个相同类型的礼物动画同时展示。
因为这是一个逻辑上特别极端的情况,所以这里没有给出效果图。

问题原因

这个问题原因其实就是因为:取缓存到动画开始这段时间内收到一条与取出缓存相同类型的消息,导致这个新的消息在做动画检测时没有检测出来,所以新的消息可能也会作为新的动画组开始展示。

问题解决

这里的解决办法是将取缓存到动画开始这个时间缩减到最短,也就是在开始展示动画前就将cell的动画状态从AnimationStateNone设置成AnimationStateShowing。
关于这个问题,有兴趣的可以自行测试,测试时记得要增大取缓存到开始动画这段时间。具体操作就是:增大cell的显示动画时间,并且等cell的显示动画完成再将cell的动画状态从AnimationStateNone设置成AnimationStateShowing。(如果有测试出问题的,记得将问题效果的gif图分享给我!拜谢了!)

问题四

解决一个问题,就会带来新的问题。这里给动画做了这么多的缓存之后带来的新的问题是什么呢!想必测试过的应该已经发现了:连送按钮已经隐藏了,但是连乘动画还在执行,这肯定是不合逻辑的。

对于这个问题,只有在项目中有要求出现连送按钮才会出现,而且出现了也不一定算是问题(映客也没解决这个问题),所以这里就不解决这个问题了,如果确实有要求的,这里提供下思路:因为展示动画和连乘动画的动画时间都是确定的,所以很容易计算出执行完当前动画组需要的时间。然后每接收到一个连乘动画就对这个时间进行更新,并用代理或其它的形式将这个时间值传递出去,最后根据这个值对连送按钮进行控制就可以了。(当然了,有实现了这个思路或是有更好思路的,方便的话,也请分享给我,再次拜谢了!)

一个好的功能应该除了具有易用性之外,还应该具有良好的扩展性。

扩展

因为项目的需求不同,所以对展示动画与隐藏动画的要求也各部相同。这里就提供了对这连个动画自定义的接口,接口名如下:

/**
 *  自定义展示动画
 *
 *  @param flag 是否带有连乘动画
 */
- (void)customDisplayAnimationOfShowShakeAnimation:(BOOL)flag;
/**
 *  自定义隐藏动画
 *
 *  @param flag 是否带有连乘动画
 */
- (void)customHideAnimationOfShowShakeAnimation:(BOOL)flag;

如果想对这两动画进行简单的自定义,就可以在自定义cell中重写这两方法。需要注意的是,这两方法是在UIView封装的动画的animations回调中调用,所以只用修改cell的frame就够了。

一般项目中通过这种方法自定义cell的展示和隐藏动画就可以满足需求,如果项目中确实需要更绚丽的动画效果,就需要修改PrentViewCell的showAnimationWithModel:showShakeAnimation:prepare:completion:方法和hiddenAnimationOfShowShake:方法中的动画代码。

当然,还有其它的地方可以扩展,例如:让礼物消息只在指定的cell上展示,如VIP用户发送的礼物消息,在特定的位置上展示;还可以对消息的展示优先级进行区分,如不同等级的用户展示消息的优先级就不一样,等等这些都是有可能项目需要的需求。这里就不一一对这些需求进行实现了,关于优化后的Demo,大家可以点击这里下载。

最后,还是开篇那句话:个人的能力有限,肯定还有很多我没有发现到的问题,如果大家在使用过程中有遇到其它的问题,欢迎大家及时指出,我好及时完善。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • 最近做了个直播项目,需要用到弹幕和刷礼物。在网上找了许多开源代码,发现都不是很适合自己的项目需求,于是利用空余时间...
    Rasping阅读 4,648评论 23 40
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,019评论 4 62
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,455评论 25 707
  • 记忆已经模糊了太多太多,因为想不起的东西,就那么一直被遗忘了,故事的开始和结束都不再是故事的重点了,享受的只是过程...
    一空一白阅读 135评论 0 0