SwiftUI Form中动态切换Picker时出现EXC_BAD_ACCESS崩溃问题
问题原因
这个崩溃是SwiftUI WheelPickerStyle 动态加载场景下的已知底层bug:当你切换到Picker Three时,Picker Two会被从视图树中移除,但SwiftUI内部没有正确释放之前和pickerTwoSelection绑定的内存指针;等你切回Picker Two重新加载滚轮选择器时,框架内部错误访问了已经释放的旧指针,就触发了EXC_BAD_ACCESS崩溃。
这个问题和你当前使用字符串类型作为选择变量的实现完全无关,不需要做字符串转整数再反向映射的修改。
解决方案
只需要给动态显示的Picker Two添加唯一标识,强制SwiftUI每次加载它时都视为全新视图,不复用之前的错误缓存即可,修改点仅一行:在Picker Two的pickerStyle修饰符后添加.id(pickerTwoVisible)。
修改后完整代码
import SwiftUI struct ContentView: View { @State var pickerOneSelection: String = "Picker Two" @State var pickerTwoVisible: Bool = false @State var pickerTwoSelection: Int = 3 @State var pickerThreeSelection: String = "Option 1" var pickerOneOptions = ["Picker Two", "Picker Three"] var pickerThreeOptions = ["Option 1", "Option 2", "Option 3"] var body: some View { NavigationView { Form { Picker("Picker One selection", selection: $pickerOneSelection) { ForEach(pickerOneOptions, id: \.self) { Text($0) } } // End of Picker 1 if pickerOneSelection == "Picker Two" { HStack { Text("Picker Two selection") Spacer() Button(String(pickerTwoSelection)) { self.pickerTwoVisible.toggle() } } // End of HStack if pickerTwoVisible { Picker("Picker Two", selection: $pickerTwoSelection) { ForEach(0..<32, id: \.self) { Text(String($0)) } } .pickerStyle(WheelPickerStyle()) // 仅新增这一行即可解决崩溃 .id(pickerTwoVisible) } // End of pickerTwoVisible } else { Picker("Picker Three selection", selection: $pickerThreeSelection) { ForEach(pickerThreeOptions, id: \.self) { Text($0) } } // End of Picker 3 } } // End of Form } // End of NavigationView } // End of body } // End of ContentView
逻辑说明
id修饰符是SwiftUI用来标识视图唯一性的标记,当id值发生变化时,SwiftUI会直接销毁旧视图实例,重新创建全新的视图实例,不会复用之前的内存缓存,也就避开了框架内部未释放旧指针的bug。你的原有业务逻辑、选择变量的类型都不需要做任何修改。
内容的提问来源于stack exchange,提问作者ej5607
相关产品推荐
相关产品推荐

