由于暂停动画和 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)
这样的东西崩溃了。进一步调用stopAnimation
或finishAnimation
它可能仍然会崩溃,因此检查动画师的状态以确保它不会在不应该被调用的时候被调用。
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