SwiftUI中点击NavigationLink后selectedPlayers数组被重置是什么原因?
问题根因
Unable to present. Please file a bug.是SwiftUI导航框架的已知问题,触发该报错时系统会多次重绘当前页面,如果你当前页面的ViewModel没有被稳定持有,每次重绘都会生成新的ViewModel实例,selectedPlayers会被初始化为空数组,所以会出现三次空数组打印。- 默认
NavigationLink在当前页面初始化时就会构造Destination实例,不是点击跳转时才构造,所以页面初始化阶段就会访问一次viewModel.mergedPlayers,点击跳转、跳转完成的视图刷新阶段又会各访问一次,刚好对应三次空数组输出。
修复方案
- 确认ViewModel的持有方式:如果你的ViewModel是遵循
ObservableObject的类类型,必须在当前页面用@StateObject声明,不要用@ObservedObject,避免父视图重绘时ViewModel被重新创建:
@StateObject var viewModel = YourViewModel()
- 改用点击后才构造Destination的跳转实现,避免提前访问mergedPlayers:
- 若使用iOS 16及以上系统,改用
NavigationStack+navigationDestination绑定的方式实现跳转,只有跳转触发时才会构造PlayView:
// 新增跳转状态绑定 @State private var navigateToPlay = false // 替换原按钮逻辑 Button { navigateToPlay = true } label: { PrimaryButton(title: "Start game") .padding() } // 绑定跳转目标 .navigationDestination(isPresented: $navigateToPlay) { PlayView(viewModel: PlayViewModel(course: viewModel.course, players: viewModel.mergedPlayers)) }
- 若兼容iOS 15及以下系统,用
NavigationLink的isActive绑定版本,配合Lazy容器延迟构造Destination:
@State private var navigateToPlay = false NavigationLink(isActive: $navigateToPlay, destination: { LazyView { PlayView(viewModel: PlayViewModel(course: viewModel.course, players: viewModel.mergedPlayers)) } }, label: { PrimaryButton(title: "Start game") .padding() }) // 通用Lazy容器实现 struct LazyView<Content: View>: View { let content: () -> Content init(@ViewBuilder content: @escaping () -> Content) { self.content = content } var body: some View { content() } }
- 检查当前页面的上层导航容器,确保整个页面只嵌套了一层
NavigationStack(iOS16+)或NavigationView(iOS15-),多层嵌套会直接触发Unable to present报错,导致页面多次重绘。
内容的提问来源于stack exchange,提问作者tonileipo
相关产品推荐
相关产品推荐

