【问题标题】:App crashing because of paused animation and NSInternalInconsistencyException由于暂停动画和 NSInternalInconsistencyException 导致应用程序崩溃
【发布时间】:2017-07-22 16:01:19
【问题描述】:

我通过向上和向下滑动来在屏幕上和关闭屏幕上设置 UIView 的动画。我使用这段代码来做到这一点:

private var _animator: AnyObject?
@available(iOS 10.0, *)
var animator: UIViewPropertyAnimator? {
    get {
        return _animator as? UIViewPropertyAnimator
    }
    set {
        _animator = newValue
    }
}
var haveTheySwiped = false
var haveTheyNotSwiped = true

@available(iOS 10.0, *)
func handlePan(recognizer: UIPanGestureRecognizer) {
    let vel = recognizer.velocity(in: self)
        switch recognizer.state {
        case .began:
            if vel.y < 0 && !haveTheySwiped {
                animator = UIViewPropertyAnimator(duration: 1, curve: .easeOut, animations: {
                    self.backgroundImage.frame = self.backgroundImage.frame.offsetBy(dx: 0, dy: -603)
                })
                haveTheySwiped = true
                isScanVisible = true
            } else if vel.y > 0 && haveTheySwiped {
                animator = UIViewPropertyAnimator(duration: 1, curve: .easeOut, animations: {
                    self.backgroundImage.frame = self.backgroundImage.frame.offsetBy(dx: 0, dy: 603)
                })
                haveTheySwiped = false
                isScanVisible = false
            }
            animator?.pauseAnimation()
            print(backgroundImage.frame.origin)
        case .changed:
            let translation = recognizer.translation(in: backgroundImage)
            if vel.y < 0 {
                animator?.fractionComplete = translation.y / -603
            } else if vel.y > 0 && haveTheySwiped == true {
                animator?.fractionComplete = translation.y / 603
            }
        case .ended:
            animator?.continueAnimation(withTimingParameters: nil, durationFactor: 0)
        case .possible: break
        default: break
        }
}

但是,最近我遇到了一个错误。当我尝试拉起时,UIView 没有出现,然后当我抬起手指时,应用程序崩溃并出现以下错误:

*** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“释放是错误的 暂停或停止的属性动画师。属性动画师必须要么 完成动画或显式停止并在他们可以之前完成 被释放。'

有人遇到过这个吗?希望有人帮助找出导致这种情况发生的原因。任何帮助将不胜感激。提前非常感谢!

干杯, 鞋

【问题讨论】:

  • @solenoid 非常感谢您的评论!我的功能实际上与视图相关联,而不是触发动画。你能澄清一下你在说什么吗?
  • 错误基本上是在说“嘿,在我以某种方式完成回调(以适当的方式完成或取消)之前不要释放我,因为我正在另一个线程上运行”。因此,只需使用手势识别器的输入来用手指移动传入的视图。我现在不能测试它,但应该有这样的例子。
  • @solenoid 你会知道我的代码的哪一部分是这样做的吗?只是有点迷茫……哈哈哈
  • func stopAnimation(Bool) 在当前位置停止动画。必需的。 func finishAnimation(at: UIViewAnimatingPosition) 完成动画并将动画器返回到非活动状态。必需的。 - 这些可能是缺少的,对不起我的大脑放屁
  • 如果您使用pausesOnCompletion = true 修复iOS 11 中的后台错误,该应用程序也会崩溃并显示相同的错误消息。如果您激活此标志,动画师将保持状态.active,即使它已完成。当系统现在尝试清理内存时,动画师必须处于状态 .inactive 否则应用程序将崩溃。

标签: ios swift animation uikit


【解决方案1】:

如果有人在 2019 年或之后仍然遇到这种崩溃,我在动画师上遇到了类似的问题,我只需要运行 25% 的部分完成(以在 collectionView 单元格上创建微妙的模糊)。

当 cell 被 deinit 或者 VC 从 navController 中弹出时会发生崩溃。

在我的单元格的 UI 设置中,我有以下实现

之前:导致崩溃

 animator?.fractionComplete = 0.25

之后:不再崩溃

 animator?.fractionComplete = 0.25
 animator?.stopAnimation(true) 
 animator?.finishAnimation(at: .current)

这对我有用。

【讨论】:

    【解决方案2】:

    这里的错误通常是由于系统试图在动画师回到 .inactive 状态之前清除它。

    我没有看到你所有的代码。

    但一般来说,这样的事情会崩溃

      private func animating(){
        let animation = UIViewPropertyAnimator(duration: 3, curve: .linear) {
            [weak self] in
            self?.view.backgroundColor = .red
        }
    
        animation.startAnimation()
        animation.pauseAnimation()
    }
    

    动画功能完成后,系统会尝试清除你创建的 UIViewPropertyAnimator(属性不在定义范围之外),但动画暂停,这意味着仍然处于 .active 状态(animation.stopAnimation() 也是如此,只是在这种情况下它是 .stop 状态),就像我上面提到的,任何时候当您尝试在动画器重新打开之前清除它时。非活动状态,系统会抛出错误。

    因此,在这种情况下,如果您希望中途暂停或停止动画,则需要找到一种方法来保留动画师。

    例如,你可以像在viewController中创建一个属性

    var animation : UIViewPropertyAnimator!
    

    但是在允许系统清除它之前,您需要确保动画师回到 .inactive 状态,否则崩溃会再次发生。

    【讨论】:

      【解决方案3】:

      实现 stopAnimation(Bool) 然后 finishAnimation(at: UIViewAnimatingPosition) 应该可以解决问题。

      该类采用 UIViewAnimating 和 UIViewImplicitlyAnimating 协议,它定义了启动、停止和 修改你的动画。有关方法的更多信息 这些协议,请参阅 UIViewAnimating 和 UIViewImplicitlyAnimating .

      https://developer.apple.com/documentation/uikit/uiviewanimating

      func stopAnimation(Bool) 将动画停止在当前位置 职位。必填。

      func finishAnimation(at: UIViewAnimatingPosition) 完成动画并将动画师返回到非活动状态 状态。必填。

      【讨论】:

      • 嘿,感谢您的回答,但仍不清楚您希望我在哪里实施。 handlePan() 函数是今年新增的函数类型。在 WWDC 上有一个关于它的讨论。我应该在哪里添加 stopAnimation 和 finishAnimation?
      • 我手边没有mac,但我会为动画developer.apple.com/documentation/uikit/uiviewpropertyanimator/…添加一个完成处理程序,然后把它放在那里。也可以把它放在动画可能被取消的任何地方。
      • 完成块在动画正常结束后执行。如果您调用 stopAnimation(_:) 方法,如果您为该方法的参数指定 true,则不会调用完成块。如果为参数指定 false,则动画器在调用其 finishAnimation(at:) 方法后正常执行完成块。
      【解决方案4】:

      Swift 5.x:

      animator?.stopAnimation(true)
      if let animator = animator, animator.state != .inactive {
          animator.finishAnimation(at: .current)
      }
      

      解决了我们案例中的问题。

      【讨论】:

        【解决方案5】:

        我遇到了一个间歇性发生的类似错误。像animator.startAnimation(afterDelay: 1) 这样的东西崩溃了。进一步调用stopAnimationfinishAnimation 它可能仍然会崩溃,因此检查动画师的状态以确保它不会在不应该被调用的时候被调用。

        if animator.state == .inactive {
        animator.startAnimation(afterDelay: 1) 
        }
        

        根据您的实施,您可以以不同的方式处理它。但是检查动画师的状态将确保不会调用导致崩溃的命令。

        在 OP 的情况下可能不会完全有帮助,但这个答案首先出现在动画师需要处于特定状态的类似错误中。

        【讨论】:

          【解决方案6】:

          动画师的状态应该是.inactive。 要实现这一点,您只需在适当的时候致电animator.stopAnimation(true)

          我在 ViewController 中使用它,离开屏幕时发生了崩溃。我需要在super.viewDidDisappear(animated) 之前调用它。

          【讨论】:

            【解决方案7】:

            我遇到了同样的问题,结合这个问题的知识帮助我解决了这个问题:

            override func viewWillDisappear(_ animated: Bool) {
                
                articleHeader?.animator.stopAnimation(true)
                
                if let animator = articleHeader?.animator, animator.state != .inactive {
                    animator.finishAnimation(at: .current)
                }
            }
            

            @programmingbeginner 和他的输入 "但是在允许系统清除它之前,您需要确保动画师回到 .inactive 状态,否则会发生崩溃再次。”帮助我了解我们需要在 UIViewController 从导航堆栈中弹出之前返回到 .inactive。执行此操作的地方是 viewWillDisappear()。

            您还需要在 UICollectionView 中保留对动画师的引用(我的动画师在 ArticleHeader 视图中)。

            @atereshkov:我正在使用他的代码来检查动画师是否仍然处于活动状态。

            在 UICollectionViewController 中保持对 ArticleHeader 动画器的引用:

            var articleHeader: ArticleHeader?
            
            override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
                // assign the header here
                articleHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: ArticleHeader.reuseIdentifier, for: indexPath) as? ArticleHeader
                
                // do any header configuration here
               
                return articleHeader!
            }
            

            希望它对未来的人有所帮助。

            【讨论】:

              猜你喜欢
              • 2012-01-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-03-17
              • 2016-08-05
              • 1970-01-01
              相关资源
              最近更新 更多