SwiftUI处理弹窗最后一个邀请时出现Index Out Of Range崩溃如何解决
崩溃根因分析
你遇到的崩溃确实是状态不同步导致的,使用PageTabViewStyle的TabView存在SwiftUI已知实现缺陷:当绑定的ForEach数据源数组突然变为空时,内部依赖的UICollectionView会触发索引越界崩溃。你当前代码中独立维护的sheetCount和groupHubVM.pendingInviteViewModels是两套独立状态,执行顺序的不确定性会导致数组先被清空、sheetCount还未更新的时间差出现,此时TabView渲染空数据源直接触发崩溃。
优化方案
核心思路是消除重复状态,所有逻辑唯一依赖pendingInviteViewModels数据源,同时加空状态保护避免TabView触底崩溃:
- 移除独立维护的
sheetCount状态,从根源避免状态不同步 - 增加空数据源占位,数组为空时不渲染TabView
- 用
onChange监听数据源数量,为空时自动关闭弹窗
修改后完整代码
PendingGroupsSheet 实现
struct PendingGroupsSheet: View { @ObservedObject var groupHubVM: GroupHubViewModel @Environment(\.presentationMode) var presentationMode init(groupHubVM: GroupHubViewModel) { self.groupHubVM = groupHubVM } var body: some View { // 空数据源保护:数组为空时渲染透明占位,直接触发关闭 if groupHubVM.pendingInviteViewModels.isEmpty { Color.clear .onAppear { presentationMode.wrappedValue.dismiss() } } else { TabView { ForEach(groupHubVM.pendingInviteViewModels) { singleGroupVM in PendingGroupInviteView( singleGroupVM: singleGroupVM, onAcceptDecline: {} // 无需手动计数,交给监听逻辑处理 ) } } .tabViewStyle(PageTabViewStyle()) // 自动监听数据源变化,为空时立即关闭弹窗 .onChange(of: groupHubVM.pendingInviteViewModels.count) { newCount in if newCount == 0 { presentationMode.wrappedValue.dismiss() } } } } }
按钮逻辑优化(可选,进一步降低崩溃概率)
如果你的邀请处理是同步操作,可以调整执行顺序,处理最后一个邀请时优先关闭弹窗,再修改数据源,彻底避免TabView渲染空数组:
Button(action: { let isLast = groupHubVM.pendingInviteViewModels.count == 1 if isLast { presentationMode.wrappedValue.dismiss() } do { try singleGroupVM.declineGroupInvitation() } catch { print(error.localizedDescription) } }){ Text("Decline") } .buttonStyle(RoundedRectangleBlackButtonStyle()) .padding()
使用该优化时,需要将presentationMode或者关闭回调传入PendingGroupInviteView即可。
内容的提问来源于stack exchange,提问作者Charlie Page
相关产品推荐
相关产品推荐

