iOS16中SwiftUI动画切换SF Symbol的symbolRenderingMode致崩溃
iOS 16下SF Symbol切换渲染模式加动画触发崩溃问题分析
问题说明
在iOS 16开发中,给SF Symbol的Image切换.symbolRenderingMode同时应用.animation时,会随机触发EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)崩溃,且无有效堆栈跟踪,异常指向主文件的@main标记。移除动画或保持渲染模式恒定就能避免崩溃,希望实现渲染模式的过渡效果,复现代码如下:
import SwiftUI struct ContentView: View { @State var mode = 0 var modeName: String { mode == 0 ? "Palette" : mode == 1 ? "Multicolor" : "Monochrome" } var nextModeName: String { mode == 0 ? "Multicolor" : mode == 1 ? "Monochrome" : "Palette" } var body: some View { VStack { Image(systemName: "list.bullet.clipboard") .font(.system(size: 50)) .symbolRenderingMode(mode == 0 ? .palette : mode == 1 ? .multicolor : .monochrome) .foregroundStyle(.primary, .secondary) .padding() Text("Current SRM: \(modeName)") Button("Tap to set SRM to: \(nextModeName)", action: {mode = mode == 2 ? 0 : mode + 1}) } // 注释此行可停止崩溃 .animation(.linear, value: mode) } }
问题判定
这是iOS 16的SwiftUI SDK Bug,不是你的代码实现问题。原因是SwiftUI在动画过程中切换SF Symbol的渲染模式时,底层渲染管线出现了未处理的冲突,无有效堆栈也说明崩溃发生在系统框架内部,而非业务代码逻辑错误。
过渡效果替代实现
要实现渲染模式的平滑过渡,不能直接给同一个Image的.symbolRenderingMode加动画,可通过多Image叠加+透明度切换的方式规避Bug,示例代码如下:
import SwiftUI struct ContentView: View { @State var mode = 0 var modeName: String { mode == 0 ? "Palette" : mode == 1 ? "Multicolor" : "Monochrome" } var nextModeName: String { mode == 0 ? "Multicolor" : mode == 1 ? "Monochrome" : "Palette" } var body: some View { VStack { ZStack { // 对应Palette模式的Image Image(systemName: "list.bullet.clipboard") .font(.system(size: 50)) .symbolRenderingMode(.palette) .foregroundStyle(.primary, .secondary) .opacity(mode == 0 ? 1 : 0) // 对应Multicolor模式的Image Image(systemName: "list.bullet.clipboard") .font(.system(size: 50)) .symbolRenderingMode(.multicolor) .opacity(mode == 1 ? 1 : 0) // 对应Monochrome模式的Image Image(systemName: "list.bullet.clipboard") .font(.system(size: 50)) .symbolRenderingMode(.monochrome) .opacity(mode == 2 ? 1 : 0) } .padding() Text("Current SRM: \(modeName)") Button("Tap to set SRM to: \(nextModeName)", action: { withAnimation(.linear) { mode = mode == 2 ? 0 : mode + 1 } }) } } }
方案说明
- 用
ZStack叠加三个分别设置好对应渲染模式的Image - 通过
opacity控制当前模式对应的Image显示,其他隐藏 - 用
withAnimation包裹状态变化,实现平滑的透明度过渡效果,既达成了渲染模式切换的视觉过渡,又避开了系统Bug
内容的提问来源于stack exchange,提问作者Greg Whatley
相关产品推荐
相关产品推荐

