CAAnimationGroup动画执行时间比设置的duration小

今天遇到一个问题,使用CAAnimationGroup实现的点赞动画设置的duration为1秒种,但是实际的动画过程很短,一下就完成,明显小于自己的预设时间,为了找到问题,实现CAAnimationDelegate协议中的- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag方法,在该方法中打断点,观察布尔值flag的变化。

//当动画终止时调用该方法,
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {

}

打断点发现,动画执行到该方法时,flag为NO,表示动画并没有按照预期完成,经过调试一步步发现,是因为调用了[self.tableView reloadData]将原有的动画过程给打断了,所以出现上述情况,表现为动画极快的结束,停止在自己预设的位置上。

RACSignal 订阅信号量(结果行不通)

为了解决这个问题,首先想到的解决办法是看是否能将【self.tableview reloadData】替换掉,或者不调用(我这个需求是评论点赞的动画,如果将这句话去掉,会导致一个问题,在同一个界面中热门评论和全部评论相同的评论在一个界面的话,点赞一个(比如这个在热门评论中),另一个不会跟随变化(这个在全部评论中,并且它们在都在同一个可见的界面上),所以这样行不通);

为了解决这个问题,需要换一种思路,另外一种思路是:
在- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag协议方法中,根据布尔值flag来发出信号量,在调用这个动画所在的类中订阅信号。
相关代码如下:

.h文件
@property (nonatomic, strong) RACSignal *animtationCompleteSignal;

.m文件
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
      if (flag) {
     self.animationCompleteSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
       [subscribe sendComplete];
        return nil;
    }];
  }
}

然后在调用这个类(计为类A)的类B中,订阅这个信号,
代码如下:
[a.animationCompleteSignal subscribeNext:^(id x) {

} complete {
//刷新的代码
[self.tableView reloadData];
}];
之后就发现无法订阅带信号,因为都是在主线程中执行的代码,先执行的订阅的代码,等到动画快要结束时才创建的信号量,所以这种方法行不太同,也有尝试将代码调整优先级,但是依旧未起作用。

上面的方法废弃,但是想到了一个比较传统的方法,就是使用block代码块来实现这种功能

使用block代码块来实现(结果可行,代码比较繁琐)

.h文件中
@property (nonatomic, copy) dispatch_block_t animationCompleteBlock;

.m文件中
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag  {
 if (flag) {
   if (self.animationCompleteBlock) {
    self.animationCompleteBlock();
 }
}
}

之后在类B中,
实现这个代码块

@weakify(self)
a.animationCompleteBlock =^(void)  {
      @strongify(self)
     [self.tableView relaodData];
}

这样写可以达到我们的目的,就是在动画完成之后执行动画完成的block中的代码。
但是就是遇到新的问题,现在是点赞的过程中热门评论和全部评论中同一个评论在同一个界面上可见时,点赞时动画效果包括变化都是相同的,符合我们的要求,但是取消点赞时因为没有刷新就会出现不同步的问题,我们可以在取消点赞时使用相同方法来解决。

使用RACObserve订阅实现

上面那个方法虽然可以解决问题,但是代码太过繁琐,遇到这种问题,首先还是想到的使用RAC的订阅来实现,上面的订阅有问题,所以我们可以尝试换个思路来解决。

我们可以考虑使用RACObserve观察cell对象(整个界面是使用UITableView实现的,每条评论都是一个UITableViewCell),我们可以观察cell中点赞数量的变化,一旦点赞数量发生变化,就触发某个方法,(点赞的时候同一条评论的likeCount变化是同步的。
我们可以在cell的setter方法中添加订阅

在cell的.m文件中的setComment方法中 
- (void) setComment:(Comment *)comment 
{
[RACObserve(post, likeCount) subscribeNext:^(id x) {
  //
使用逻辑代码给点赞数量的label和图片选择赋值
   }];
}

上面的写法没有问题,但是运行依旧出错,原因是UITableViewCell的重用机制,在开始时,假设总计有20个cell,初始界面展示13个cell,那么会创建14个cell,剩下的6个会从重用池中取出复用,(14个的原因是当滑动时展示第14个的半个cell时不会导致卡顿)。
因为复用的关系,对cell添加的监听会混乱,所以我们必须保证每个cell对应的都是正确的监听。

为了达到这个目的,

B.h
@property (nonatomic) RACDisposable *disposable;

B.m中 在添加监听之前判断监听对象是否已经存在,如果存在则将其释放

- (void) setComment:(Comment *)comment 
{
if  (self.disposable) {
   [self.disposable dispose];
}
 self.disposable = [RACObserve(post, likeCount) subscribeNext:^(id x) {
  //
使用逻辑代码给点赞数量的label和图片选择赋值
   }];
}

不再使用[self.tableView reloadData]方法。

你可能感兴趣的:(CAAnimationGroup动画执行时间比设置的duration小)