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

使用UINavigationController时SwiftUI的onChange未触发问题求助

SwiftUI与UIKit混合导航下ObservableObject的onChange不触发问题

项目背景

  • 需支持iOS 14
  • 采用SwiftUI+UIKit混合开发,必须使用UINavigationController作为窗口根控制器(否则无法推送UIKit视图控制器)

根控制器配置代码

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = scene as? UIWindowScene else {
        return
    }
    
    let window = UIWindow(windowScene: windowScene)
    window.makeKeyAndVisible()
    window.overrideUserInterfaceStyle = .light
    self.window = window

    // UIKit Navigation 作为根控制器
    let rootView = AnyView(SwiftUIView1())
    let rootVC = UIHostingController(rootView: rootView)
    let rootNavC = UINavigationController(rootViewController: rootVC)
    window.rootViewController = rootNavC
}

注:原代码中存在笔误rootHubVC,已修正为rootVC

SwiftUIView1与ObservableObject定义

class TestingState: ObservableObject, Equatable {
    static func == (lhs: TestingState, rhs: TestingState) -> Bool {
        lhs.currentJourneyLevel == rhs.currentJourneyLevel
    }
    
    @Published var currentJourneyLevel: Int {
        willSet {
            debugPrint("##### currentJourneyLevel will be set from \(currentJourneyLevel) to \(newValue)")
        }
    }
    
    init() {
        currentJourneyLevel = 1
    }
}

struct SwiftUIView1: View {
    @StateObject private var testingState = TestingState()
    @State var isActived = false {
        didSet {
            debugPrint("##### isActived: \(isActived)")
        }
    }

    var body: some View {
        VStack (spacing: 30) {
            Button("NextPage") {
                testingState.currentJourneyLevel = 2
            }
            
            NavigationLink(
                destination: SwiftUIView2(state: testingState),
                isActive: $isActived
            ) { EmptyView() }
        }
        .onChange(of: testingState.currentJourneyLevel) { currentJourneyLevel in
            debugPrint("##### currentJourneyLevel is onChange to: \(currentJourneyLevel)")
            isActived = currentJourneyLevel == 2
        }
        .navigationTitle("SwiftUIView1")
        .navigationBarTitleDisplayMode(.inline)
    }
}

注:原代码中存在两处笔误已修正:

  • TestingState的==方法中错误比较lhs自身属性,已改为比较rhs对应属性
  • NavigationLink的目标视图错误写为SwiftUIView1,已改为SwiftUIView2

SwiftUIView2代码

struct SwiftUIView2: View {
    private var state: TestingState

    init(state: TestingState) {
        self.state = state
    }
    
    var body: some View {
        ZStack {
            VStack(spacing: 10) {
                Button("Back") {
                    state.currentJourneyLevel = 1
                }
            }
            .navigationTitle("SwiftUIView2")
        }
    }
}

问题现象

  1. 点击"NextPage"按钮时功能正常,日志输出:
"##### currentJourneyLevel will be set from 1 to 2"
"##### currentJourneyLevel is onChange to: 2"
"##### isActived: true"
  1. 点击"Back"按钮时,仅输出:
"##### currentJourneyLevel will be set from 2 to 1"

currentJourneyLevel已变更,但SwiftUIView1中的onChange闭包未触发。
3. 若改用纯SwiftUI的NavigationView导航,点击"Back"按钮时onChange正常触发,日志输出:

"##### currentJourneyLevel will be set from 2 to 1"
"##### currentJourneyLevel is onChange to: 1"
"##### isActived: false"

提问

如何让onChange在UINavigationController作为根控制器的情况下正常触发?或是我的代码存在操作错误?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:07:35