【问题标题】:Animation completion block goes haywire after dismissing view动画完成块在关闭视图后出现问题
【发布时间】:2018-05-18 17:45:21
【问题描述】:

我有一个详细视图控制器,其中包含一个带有动画图像视图的重复轮播,如下所示:

func animateCarousel1(){
    UIView.animate(withDuration: 1, delay: 3, options: .curveEaseInOut, animations: 
        //image animation
    },completion: { (_) -> Void in
        print("animation 1 complete")
        self.animateCarousel2() 
                  })
    }
func animateCarousel2(){
    UIView.animate(withDuration: 1, delay: 3, options: .curveEaseInOut, animations: 
        //image animation
    },completion: { (_) -> Void in
        print("animation 2 complete")
        self.animateCarousel1() 
                  })
    }

在弹出这个视图并返回父视图时,我看到在调试控制台中,函数在后台继续被调用,重复同时,无限。

模拟器中的 CPU 使用率也跃升至 90%。

在弹出视图控制器之前我需要做某种 deinit 吗?我似乎无法理解这个。

【问题讨论】:

  • 动画取消时调用完成处理程序。在调用另一个参数之前检查闭包的第一个参数(一个布尔值,finished,表示它是否成功完成)。
  • 或者也许使用关键帧动画来重复一系列动画,而不是使用这种完成块模式。
  • 我不知道我的完成处理程序在动画被取消时也被调用了,我只是假设它们只在动画实际完成时调用。谢谢罗!

标签: ios swift uiview uinavigationcontroller


【解决方案1】:

问题是即使动画完成也会调用完成块。所以有几种可能的解决方案:

  1. 检查完成处理程序的finished 参数:

    func animateCarousel1() {
        UIView.animate(withDuration: 1, delay: 3, options: .curveEaseInOut, animations: {
            //image animation
        }, completion: { finished in
            print("animation 1 complete")
            if finished { self.animateCarousel2() }
        })
    }
    
    func animateCarousel2() {
        UIView.animate(withDuration: 1, delay: 3, options: .curveEaseInOut, animations: {
            //image animation
        }, completion: { finished in
            print("animation 2 complete")
            if finished { self.animateCarousel1() }
        })
    }
    
  2. 使用不同的动画技术,不需要这些动画例程之间的循环引用,例如:

    func animateCarousel() {
        UIView.animateKeyframes(withDuration: 8, delay: 3, options: .repeat, animations: {
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.125) {
                // animation 1
            }
            UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.125) {
                // animation 2
            }
        }, completion: nil)
    }
    

【讨论】:

    【解决方案2】:

    这可能解决了你可以看到这个帖子link here的问题

    在 deinit() 控制器方法或 viewDidDissapear() 上使用,试试下面的代码

    deinit {
        print("deinit \(NSStringFromClass(self.classForCoder).components(separatedBy: ".").last ?? "")") // print viewcontroller deallocated
        self.view_for_remove_animations.layer.removeAllAnimations() // Forze delete animations
    }
    

     override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        print("viewDidDisappear \(NSStringFromClass(self.classForCoder).components(separatedBy: ".").last ?? "")") // print viewcontroller deallocated
        self.view_for_remove_animations.layer.removeAllAnimations() // Forze delete animations
    }
    

    试试看,然后发送反馈

    【讨论】:

      【解决方案3】:

      原因是在动画块中,你使用了 self 的强引用,这就是为什么当你弹出这个 viewcontroller 时它的引用计数仍然不是 0,因为 ARC 无法释放这个 view controller 的引用。

      [weak self] 的概念。您可以像下面这样修改您的代码,然后在弹出后您将不会在调试控制台中看到这些方法调用。原因:weak self 不会增加引用计数,ARC 就能移除对象的引用

      func startAnimation() {
          UIView.animate(withDuration: 0.4, animations: {[weak self] in
              self?.animateView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
              print("startAnimation")
          }, completion: {[weak self]
              finished in
              self?.startAnimation2()
          })
      }
      func startAnimation2() {
          UIView.animate(withDuration: 0.4, animations: {[weak self] in
              self?.animateView.frame = CGRect(x: 100, y: 0, width: 100, height: 100)
              print("startAnimation2")
          }, completion: {[weak self]
              finished in
              self?.startAnimation()
          })
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-09
        • 2016-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-15
        相关资源
        最近更新 更多