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

SwiftUI中NavigationLink引发无限循环问题求助

问题现象

在SwiftUI开发中,某一个NavigationLink触发了无限循环,具体表现为ViewAViewModel的init方法被反复调用(控制台持续输出VIEW A INIT)。该问题仅在iOS 18.2.1真机上出现,iOS 18.0模拟器无此异常。即使移除ViewAView和ViewAViewModel中的所有可观测性代码,问题依然存在。将视图模型的创建从计算属性移至主视图的init方法后,无限循环问题消失。


相关代码

主视图body代码

var body: some View {
    List {
        viewA
    }
    .listStyle(.insetGrouped)
    .navigationTitle(viewModel.game.teamName)
    .navigationBarTitleDisplayMode(.inline)
}
private var viewA: some View {
    CustomNavigationLink {
        ViewAView(viewModel: viewModel.viewAViewModel)
    } label: {
        Text("View A")
    }
}

计分卡管理器视图模型定义(原计算属性)

var viewAViewModel: ScorecardManagerViewModel {
    ViewAViewModel(game: game)
}

ViewA视图模型初始化方法

init(game: Game) {
    self.game = game
    self.scenarios = game.scenariosAsArray() ?? []
    shouldShowInitialAddScenario()
    updateCampaignScore()
    print("VIEW A INIT")
}

CustomNavigationLink实现

struct CustomNavigationLink<Destination, Label>: View where Destination : View, Label : View {
    
    var destination: () -> Destination
    let label: () -> Label
    
    var body: some View {
        HStack {
            label()
            Spacer()
            Image(systemName: "chevron.right")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 7)
                .fontWeight(.bold)
                .foregroundColor(.purple)
        }
        .background(
            NavigationLink {
                destination()
            } label: {
                Text("")
            }
            .opacity(0)
        )
    }
}

问题原因

核心问题在于视图模型的计算属性定义:每次访问viewModel.viewAViewModel都会创建一个全新的ViewAViewModel实例。在iOS 18.2.1真机的SwiftUI渲染机制下,NavigationLink的目标视图闭包被频繁求值(可能是系统对视图布局、状态的检查逻辑发生了变化),导致计算属性被反复触发,进而不断初始化ViewModel,形成无限循环。

解决方案

  1. 将视图模型改为存储属性:在主视图的ViewModel初始化时提前创建ViewAViewModel,并存储为实例属性,避免每次访问都生成新对象:
class MainViewModel {
    let game: Game
    let viewAViewModel: ScorecardManagerViewModel
    
    init(game: Game) {
        self.game = game
        // 提前初始化视图模型,仅创建一次
        self.viewAViewModel = ViewAViewModel(game: game)
    }
}
  1. 确认闭包求值时机:如果自定义CustomNavigationLink的destination闭包存在被重复调用的可能,可以考虑用@autoclosure修饰参数,优化闭包的执行时机,但当前问题的核心还是视图模型的创建方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 12:47:16