You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中点击NavigationLink后selectedPlayers数组被重置是什么原因?

问题根因
  • Unable to present. Please file a bug.是SwiftUI导航框架的已知问题,触发该报错时系统会多次重绘当前页面,如果你当前页面的ViewModel没有被稳定持有,每次重绘都会生成新的ViewModel实例,selectedPlayers会被初始化为空数组,所以会出现三次空数组打印。
  • 默认NavigationLink在当前页面初始化时就会构造Destination实例,不是点击跳转时才构造,所以页面初始化阶段就会访问一次viewModel.mergedPlayers,点击跳转、跳转完成的视图刷新阶段又会各访问一次,刚好对应三次空数组输出。
修复方案
  1. 确认ViewModel的持有方式:如果你的ViewModel是遵循ObservableObject的类类型,必须在当前页面用@StateObject声明,不要用@ObservedObject,避免父视图重绘时ViewModel被重新创建:
@StateObject var viewModel = YourViewModel()
  1. 改用点击后才构造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()
  }
}
  1. 检查当前页面的上层导航容器,确保整个页面只嵌套了一层NavigationStack(iOS16+)或NavigationView(iOS15-),多层嵌套会直接触发Unable to present报错,导致页面多次重绘。

内容的提问来源于stack exchange,提问作者tonileipo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 09:15:02