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

SwiftUI中如何将导航栏按钮动作绑定至ViewControllerWrapper

解决SwiftUI导航按钮调用UIKit ViewController方法的问题

针对混合UIKit与SwiftUI技术栈的场景,要让SwiftUI导航栏按钮触发UIKit侧ClockMainViewController的指定方法,这里提供两种实用方案,同时替换掉废弃的navigationBarItemsAPI:

方案1:基于SwiftUI单向数据流的Binding触发法

这种方法符合SwiftUI的设计理念,通过@Binding传递触发信号,在UIKit封装器中响应并调用目标方法。

步骤1:修改ClockMainViewControllerWrapper

import SwiftUI

struct ClockMainViewControllerWrapper: UIViewControllerRepresentable {
    // 绑定触发信号,用于通知UIKit侧执行方法
    @Binding var shouldTriggerEdit: Bool
    
    func makeUIViewController(context: Context) -> ClockMainViewController {
        ClockMainViewController()
    }
    
    func updateUIViewController(_ uiViewController: ClockMainViewController, context: Context) {
        // 当触发信号变为true时,调用目标方法并重置信号
        guard shouldTriggerEdit else { return }
        uiViewController.startEditTransition() // 替换为你实际要调用的方法名
        shouldTriggerEdit = false
    }
}

步骤2:在SwiftUI主视图中使用

struct MainMenuView: View {
    // 定义触发状态变量
    @State private var triggerClockEdit = false
    
    var body: some View {
        NavigationStack { // iOS 16+用NavigationStack,iOS 15及以下用NavigationView
            ClockMainViewControllerWrapper(shouldTriggerEdit: $triggerClockEdit)
                .navigationTitle("title")
                .navigationBarTitleDisplayMode(.inline)
                .toolbar {
                    // 用ToolbarItem替代废弃的navigationBarItems
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button(action: {
                            // 切换触发状态
                            triggerClockEdit = true
                        }) {
                            Image(systemName: "pencil")
                        }
                    }
                }
        }
    }
}

方案2:直接持有ViewController引用(更直接)

如果不需要严格遵循SwiftUI数据流,可通过ObservableObject持有ViewController的弱引用,直接调用方法。

步骤1:定义引用管理类

import SwiftUI

class ClockVCReference: ObservableObject {
    // 弱引用避免内存泄漏
    weak var viewController: ClockMainViewController?
}

步骤2:修改ClockMainViewControllerWrapper

struct ClockMainViewControllerWrapper: UIViewControllerRepresentable {
    @ObservedObject var vcReference: ClockVCReference
    
    func makeUIViewController(context: Context) -> ClockMainViewController {
        let vc = ClockMainViewController()
        vcReference.viewController = vc
        return vc
    }
    
    func updateUIViewController(_ uiViewController: ClockMainViewController, context: Context) {}
}

步骤3:在SwiftUI主视图中使用

struct MainMenuView: View {
    @StateObject private var clockVCRef = ClockVCReference()
    
    var body: some View {
        NavigationStack {
            ClockMainViewControllerWrapper(vcReference: clockVCRef)
                .navigationTitle("title")
                .navigationBarTitleDisplayMode(.inline)
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button(action: {
                            // 直接调用ViewController的方法,注意判空
                            clockVCRef.viewController?.startEditTransition()
                        }) {
                            Image(systemName: "pencil")
                        }
                    }
                }
        }
    }
}

关键注意点

  • 废弃API替换:务必用toolbar+ToolbarItem替代navigationBarItems,这是SwiftUI当前的标准实现。
  • 内存安全:所有对UIKit ViewController的引用必须用weak,防止循环引用导致内存泄漏。
  • 方法调用时机:方案1通过updateUIViewController确保ViewController已完成初始化;方案2需注意判空,避免ViewController未加载时调用方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 14:20:34