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
相关产品推荐
相关产品推荐

