You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS17中使用PhaseAnimator时Dismiss视图致App崩溃求助

iOS 17 PhaseAnimator 视图 Dismiss 时崩溃问题及解决方案

问题说明

使用 iOS 17 新增的 PhaseAnimator 实现动画效果时,若在动画运行期间 dismiss 包含该动画的视图,App 会触发并发访问崩溃。已通过小型项目复现问题,并向苹果提交反馈(编号 FB13655444)。

复现代码

struct ContentView: View {
    @State var isPresenting = false

    var body: some View {
        Button("Present", action: {
            isPresenting = true
        })
        .sheet(isPresented: $isPresenting, content: {
            AnimatedView()
        })
    }
}

struct AnimatedView: View {
    @Environment(\.dismiss) var dismiss

    var body: some View {
        VStack {
            Text("Hello")
                .phaseAnimator([1, 1.3]) { content, phase in
                    content.scaleEffect(
                        CGSize(width: phase, height: phase),
                        anchor: .center
                    )
                }

            Button("Dismiss", action: {
                dismiss()
            })
        }
    }
}

崩溃栈信息

Simultaneous accesses to 0x102b079c0, but modification requires exclusive access.
Previous access (a modification) started at SwiftUI`OUTLINED_FUNCTION_0 + 8352 (0x1c571eb30).
Current access (a read) started at:
0    libswiftCore.dylib                 0x0000000192c95ec8 swift::runtime::AccessSet::insert(swift::runtime::Access*, void*, void*, swift::ExclusivityFlags) + 428
1    libswiftCore.dylib                 0x0000000192c960dc swift_beginAccess + 72
2    SwiftUI                            0x00000001c571ca90 OUTLINED_FUNCTION_0 + 10144
3    SwiftUI                            0x00000001c583a898 OUTLINED_FUNCTION_21 + 11580
4    SwiftUI                            0x00000001c4cccec4 OUTLINED_FUNCTION_31 + 7832
5    SwiftUI                            0x00000001c4cccec4 OUTLINED_FUNCTION_31 + 7556
6    SwiftUI                            0x00000001c59814f8 OUTLINED_FUNCTION_31 + 1452
7    SwiftUI                            0x00000001c57ab900 OUTLINED_FUNCTION_83 + 84188
8    SwiftUI                            0x00000001c57ab900 OUTLINED_FUNCTION_83 + 79588
9    SwiftUI                            0x00000001c57ab900 OUTLINED_FUNCTION_83 + 79548
10   SwiftUI                            0x00000001c57ab900 OUTLINED_FUNCTION_83 + 79680
11   AttributeGraph                     0x00000001b2c03748 __swift_instantiateConcreteTypeFromMangledName + 4000
12   AttributeGraph                     0x00000001b2bf2930 AG::Node::destroy(AG::Graph&) + 188
13   AttributeGraph                     0x00000001b2be87b0 AG::Subgraph::invalidate_now(AG::Graph&) + 1184
14   AttributeGraph                     0x00000001b2be8678 AG::Graph::invalidate_subgraphs() + 192
15   AttributeGraph                     0x00000001b2be13c8 AG::Graph::Context::~Context() + 348
16   AttributeGraph                     0x00000001b2bfa740 AGGraphInvalidate + 32
17   SwiftUI                            0x00000001c571ca90 OUTLINED_FUNCTION_0 + 8400
18   SwiftUI                            0x00000001c583a898 OUTLINED_FUNCTION_21 + 32348
19   SwiftUI                            0x00000001c583a898 OUTLINED_FUNCTION_21 + 32124
20   SwiftUI                            0x00000001c583a898 OUTLINED_FUNCTION_21 + 32392
21   libobjc.A.dylib                    0x0000000180083080 AutoreleasePoolPage::releaseUntil(objc_object**) + 200
22   libobjc.A.dylib                    0x0000000180082f18 objc_autoreleasePoolPop + 256
23   CoreFoundation                     0x00000001804a62b4 _CFAutoreleasePoolPop + 28
24   CoreFoundation                     0x00000001803f0ecc __CFRunLoopPerCalloutARPEnd + 44
25   CoreFoundation                     0x00000001803eb9b8 __CFRunLoopRun + 1976
26   CoreFoundation                     0x00000001803eb368 CFRunLoopRunSpecific + 572
27   GraphicsServices                   0x000000018e9fba44 GSEventRunModal + 160
28   UIKitCore                          0x00000001852eff80 -[UIApplication _run] + 868
29   UIKitCore                          0x00000001852f3ee0 UIApplicationMain + 124
30   SwiftUI                            0x00000001c51fbfbc OUTLINED_FUNCTION_70 + 500
31   SwiftUI                            0x00000001c51fbfbc OUTLINED_FUNCTION_70 + 148
32   SwiftUI                            0x00000001c4f02f48 OUTLINED_FUNCTION_2 + 92
33   SimultaneousAccessesCrash          0x0000000102632f18 static SimultaneousAccessesCrashApp.$main() + 40
34   SimultaneousAccessesCrash          0x0000000102632fe4 main + 12

临时方案

放弃使用 PhaseAnimator,通过 .onAppear 配合一系列 withAnimation 调用实现多状态切换动画,后续动画用 DispatchQueue.main.async(after: ...) 延迟触发。该方案可行但代码不够优雅。

可靠解决方案

利用 PhaseAnimator 的 isActive 参数手动控制动画启停,在 dismiss 视图前先停止动画,避免并发访问冲突:

struct AnimatedView: View {
    @Environment(\.dismiss) var dismiss
    @State private var isAnimating = true

    var body: some View {
        VStack {
            Text("Hello")
                .phaseAnimator([1, 1.3], isActive: $isAnimating) { content, phase in
                    content.scaleEffect(
                        CGSize(width: phase, height: phase),
                        anchor: .center
                    )
                }

            Button("Dismiss", action: {
                // 先停止动画
                isAnimating = false
                // 立即dismiss即可,动画停止后不会再触发并发访问
                dismiss()
            })
        }
        // 视图消失时确保动画停止,防止意外场景触发崩溃
        .onDisappear {
            isAnimating = false
        }
    }
}

原理说明

崩溃原因是视图销毁时,PhaseAnimator 的动画仍在运行,导致对内部状态的并发读写冲突。通过 isActive 参数主动停止动画后,视图销毁时动画逻辑已终止,不会再触发访问冲突。


内容的提问来源于stack exchange,提问作者vrutberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 07:19:52