iOS15下同个List放多个Wheel样式Picker选第二个时崩溃是什么原因
问题根因
这是iOS 15 系统级的SwiftUI Bug,问题出在SwiftUI内部负责管理视图状态依赖的AttributeGraph框架:
- iOS15重构了List的单元格复用、可折叠inline控件的布局计算逻辑,当同一个List内存在多个可动态展开/收起的wheel样式Picker时,第二个Picker的选中值发生变化时,会触发两个Picker的布局递归重算,形成依赖循环,你看到的
=== AttributeGraph: cycle detected through attribute XXXX ===日志就是循环依赖的直接提示 - 循环依赖无法被SwiftUI内部打破时,系统会直接杀掉应用进程,所以不会输出常规的崩溃堆栈
- 该Bug不存在于iOS14,iOS16及后续版本中已经被官方修复,仅需要兼容iOS15的场景需要做额外处理
修复方案
以下方案均兼容iOS14+,不需要做系统版本判断:
- 方案1:替换List为ScrollView+LazyVStack(改动最小)
避开List的单元格复用逻辑即可直接解决布局循环问题,视觉效果可以通过调整padding和List的inset样式对齐:NavigationView { // 替换原有的List为如下代码 ScrollView { LazyVStack(spacing: 12) { // 原List内的所有内容原封不动放在此处 } .padding(.horizontal) } .navigationTitle("Picker") } - 方案2:给每组Picker+触发行套独立Section
List的Section会隔离内部的布局计算,避免跨Section的依赖循环:List { Section { // Picker1的触发行代码 if showPicker1 { // Picker1原有代码 } } Section { // Picker2的触发行代码 if showPicker2 { // Picker2原有代码 } } } .listStyle(.inset) - 方案3:强制Picker视图重建打断循环
给每个Picker添加.id()修饰符,绑定对应的选中状态,选中值变化时强制重建Picker视图,直接打断布局循环:Picker("", selection: $selected1) { // 原有选项逻辑不变 } .pickerStyle(.wheel) .clipped() .id(selected1) // 新增此行,第二个Picker绑定selected2即可
内容的提问来源于stack exchange,提问作者SupaBasti
相关产品推荐
相关产品推荐

