ios - UIViewPropertyAnimator 在调用 finishAnimation 后在 dealloc 时崩溃(位于 :)

标签 ios uikit

当使用 UIViewPropertyAnimator 并在 stopAnimation(false) 之后调用 finishAnimation(at:) 时:

您可以获得以下崩溃日志:

- [UIViewPropertyAnimator dealloc]

或者如果您在调试器中捕获断言(通过为 Objective-C 异常设置断点)

-[UIViewPropertyAnimator finishAnimationAtPosition:]、/BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore_Sim/UIKit-3900.12.16/UIViewPropertyAnimator.m:1981 中断言失败

由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“finishAnimationAtPosition:只能在已停止的动画制作器上调用!”

如果您设法捕获断言(崩溃日志没有多大帮助,除非您也在发布运行时捕获这些断言),您将看到它提示 finishAnimation 在不间断的动画师。

但是我的代码显示动画师总是在调用 finishAnimation 之前停止。

animator.stopAnimation(false)
animator.finishAnimation(at: .start)

什么可能导致此崩溃,调用 stopAnimation 后状态应始终停止?

最佳答案

我发生这种情况的原因是完成 block 的时间问题:

这意味着 UIViewPropertyAnimator.state (UIViewAnimatingState) 处于无效状态。由于这只是一个 Objective C 枚举,因此它可以具有超出案例中定义的任何原始值。在我崩溃的情况下,该值为 5

我正在制作一堆相互引用的链接动画,并且具有如下所示的内容:

animator.addCompletion({ _ in
    // Here I called a piece of code that eventually referenced this animator
    // and attempted to call `stopAnimation(false)` and `finishAnimation(at:)` 
    // on it causing the crash.
    //
    // You will notice if you examine the `state` of the animator here, it will have 
    // an invalid `rawValue` of 5, at least up to iOS 13.2, as this is an implementation detail.
})

解决方案是在完成 block 执行完毕之前不要尝试对动画器进行任何操作。

如果您无法避免它,适用于当前 UIKit 实现的解决方法是将 DispatchQueue.main.async 移出该完成 block ,以允许其完成。当然,这并不能保证在未来版本的 iOS 中该异步内部的状态有效。

在 Swift 上,要调试它,您可以使用以下扩展:

extension UIViewAnimatingState: CustomStringConvertible, CustomDebugStringConvertible {
    var isValid: Bool {
        switch self {
        case .inactive, .active, .stopped:
            return true
        default:
            return false
        }
    }

    public var description: String {
        switch self {
        case .inactive:
            return "inactive"
        case .active:
            return "active"
        case .stopped:
            return "stopped"
        default:
            return "\(rawValue)"
        }
    }

    public var debugDescription: String {
        return description
    }
}

因此,当您调用 stopAnimation(false)finishAnimation(at:) 时,您至少可以避免崩溃并提醒自己动画师可能存在逻辑问题:

// This is for debugging, the code below should be safe even if isValid is false
assert(animator.state.isValid, "animator state is not valid")

animator.stopAnimation(false)

if animator.state == .stopped {
    // This call is the one that can assert and crash the app
    animator.finishAnimation(at: .start)
}

关于ios - UIViewPropertyAnimator 在调用 finishAnimation 后在 dealloc 时崩溃(位于 :),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59205288/

相关文章:

ios - 如果我没有在 viewDidUnload 方法中设置属性 = nil,这意味着什么?

Javascript Youtube mp4 下载到 ios

cocoa-touch - 绘制圆并存储在 UIImage 中

ios - indexPathForSelectedRow 返回零

ios - 如何快速提高蓝牙通信速度?

ios - 如何通过应用程序从设备的照片库中删除照片?

ios - 检测主线程之外的 UI 操作

没有 UIViewRepresentable 的 SwiftUI map 覆盖

ios - 模块化滑出容器 ViewController

ios - 仅从 UIView 的 3 个侧面绘制阴影