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

为何@ObservedObject在NavigationLink中复用模型,@StateObject却不会?

SwiftUI中NavigationLink跳转时@ObservedObject与@StateObject的实例复用问题

问题现象

在iPhone模拟器中运行以下代码时,通过NavigationLink跳转至ScorePlate后,会复用上次的Model实例:

import SwiftUI
struct ContentView: View {
    @State private var showRealName = false
    var body: some View {
      NavigationView {
        VStack {
          Button("Toggle Name") {
            showRealName.toggle()
          }
          Text("Current User: \(showRealName ? "Wei Wang" : "onevcat")")
          NavigationLink("Next", destination: ScorePlate().padding(.top, 20))
        }
      }
    }
}

class Model: ObservableObject {
    init() { print("Model Created") }
    @Published var score: Int = 0
}

struct ScorePlate: View {

    @ObservedObject var model = Model()
    @State private var niceScore = false

    var body: some View {
        let _ = print("ScorePlate")
        VStack {
            Button("+1") {
                if model.score > 3 {
                    niceScore = true
                }
                model.score += 1
            }
            Text("Score: \(model.score)")
            Text("Nice? \(niceScore ? "YES" : "NO")")
            ScoreText(model: model).padding(.top, 20)
        }
    }
}

struct ScoreText: View {
    @ObservedObject var model: Model

    var body: some View {
        if model.score > 10 {
            return Text("Fantastic")
        } else if model.score > 3 {
            return Text("Good")
        } else {
            return Text("Ummmm...")
        }
    }
}

但将ScorePlate中的模型声明从@ObservedObject var model = Model()改为@StateObject var model = Model()后,复用现象消失。这和“@StateObject会复用实例、@ObservedObject会每次创建”的认知相反,原因如下:

核心原因解析

  • 纠正认知偏差:

    • @StateObject的作用是让View拥有并管理ObservableObject的生命周期,它会保证在View的整个生命周期内,对象只被初始化一次。
    • @ObservedObject是用来观察外部传入的ObservableObject,它本身不负责对象的创建和生命周期管理——在View内部直接初始化@ObservedObject的写法,其实不符合它的设计初衷。
  • @ObservedObject出现复用的原因:
    SwiftUI的NavigationLink导航栈机制会缓存已push过的View实例。第一次跳转时创建的ScorePlate实例会被保留在导航栈中,当你返回再重新跳转时,即使ContentView的body因showRealName变化重新计算、生成了新的ScorePlate()对象,导航栈依然会复用之前缓存的旧ScorePlate实例,它内部的model自然也跟着被复用了。

  • @StateObject不复用的原因:
    当使用@StateObject时,每个ScorePlate实例都拥有独立的model对象。当你从导航栈返回再重新跳转时,NavigationLink会创建全新的ScorePlate实例(而非复用旧实例),新实例的@StateObject会触发Model的初始化,因此不会出现复用现象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:56:13