由于暂停动画和 NSInternalInconsistencyException 导致应用程序崩溃

Posted

技术标签:

【中文标题】由于暂停动画和 NSInternalInconsistencyException 导致应用程序崩溃【英文标题】:App crashing because of paused animation and 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 否则应用程序将崩溃。 【参考方案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!

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

【讨论】:

以上是关于由于暂停动画和 NSInternalInconsistencyException 导致应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

在SKScene暂停时动画SKSpriteNode的alpha

iOS动画暂停和继续

如何暂停和恢复 UIView 动画(没有块动画)?

css 您可以通过更改其动画播放状态属性来“暂停”和“播放”CSS动画。将其设置为“暂停”会停止播放动画

摇摆动画暂停和恢复

暂停和恢复 AnimateWithDuration 动画 ios