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

SwiftUI子视图间引用共享数据的其他方案及跨视图触发ViewModel方法

子视图间数据共享与跨ViewModel触发方法的替代方案

一、ObservableObject共享状态容器

创建一个遵循ObservableObject的全局共享状态类,将需要跨视图同步的状态放在其中,通过@EnvironmentObject或直接注入的方式让各视图共享实例,状态变化时自动触发响应。

实现示例:

  1. 定义共享状态类:
class AppState: ObservableObject {
    @Published var settingsChanged = false
}
  1. 在App入口注入实例:
@main
struct YourApp: App {
    @StateObject private var appState = AppState()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(appState)
        }
    }
}
  1. SettingsView中修改状态:
struct SettingsView: View {
    @EnvironmentObject var appState: AppState
    @Environment(\.dismiss) private var dismiss
    
    var body: some View {
        Button("保存设置并退出") {
            appState.settingsChanged = true
            dismiss()
        }
    }
}
  1. HeaderViewModel监听状态变化:
class HeaderViewModel: ObservableObject {
    private var appState: AppState
    private var cancellables = Set<AnyCancellable>()
    
    init(appState: AppState) {
        self.appState = appState
        appState.$settingsChanged
            .filter { $0 }
            .sink { [weak self] _ in
                self?.loadData()
                self?.appState.settingsChanged = false // 重置状态避免重复触发
            }
            .store(in: &cancellables)
    }
    
    func loadData() {
        // 数据加载逻辑
    }
}

这种方式无需定时器轮询,状态变更时自动触发回调,效率更高。

二、闭包直接回调

在SettingsView中定义闭包属性,退出时调用闭包,由ContentView直接触发HeaderViewModel的方法,逻辑直接清晰。

实现示例:

  1. SettingsView添加闭包:
struct SettingsView: View {
    @Environment(\.dismiss) private var dismiss
    var onDismiss: (() -> Void)?
    
    var body: some View {
        Button("保存设置并退出") {
            dismiss()
            onDismiss?()
        }
    }
}
  1. ContentView传递闭包触发方法:
struct ContentView: View {
    @StateObject private var headerVM = HeaderViewModel()
    @State private var showSettings = false
    
    var body: some View {
        VStack {
            HeaderView(viewModel: headerVM)
            Button("打开设置") {
                showSettings = true
            }
        }
        .fullScreenCover(isPresented: $showSettings) {
            SettingsView(onDismiss: {
                headerVM.loadData()
            })
        }
    }
}

三、NotificationCenter通知中心

通过发送和接收系统通知实现跨组件通信,适合松散耦合的场景,注意监听需要及时销毁避免内存泄漏。

实现示例:

  1. 定义通知名称:
extension Notification.Name {
    static let settingsUpdated = Notification.Name("SettingsUpdated")
}
  1. SettingsView发送通知:
struct SettingsView: View {
    @Environment(\.dismiss) private var dismiss
    
    var body: some View {
        Button("保存设置并退出") {
            dismiss()
            NotificationCenter.default.post(name: .settingsUpdated, object: nil)
        }
    }
}
  1. HeaderViewModel监听通知:
class HeaderViewModel: ObservableObject {
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        NotificationCenter.default.publisher(for: .settingsUpdated)
            .sink { [weak self] _ in
                self?.loadData()
            }
            .store(in: &cancellables)
    }
    
    func loadData() {
        // 数据加载逻辑
    }
}

四、Combine Subject事件总线

创建全局事件总线,用PassthroughSubject传递类型化事件,比通知中心更安全,适合多事件类型的复杂场景。

实现示例:

  1. 定义事件总线:
enum AppEvent {
    case settingsUpdated
}

class EventBus {
    static let shared = EventBus()
    private let subject = PassthroughSubject<AppEvent, Never>()
    
    func send(_ event: AppEvent) {
        subject.send(event)
    }
    
    func publisher() -> AnyPublisher<AppEvent, Never> {
        subject.eraseToAnyPublisher()
    }
}
  1. SettingsView发送事件:
struct SettingsView: View {
    @Environment(\.dismiss) private var dismiss
    
    var body: some View {
        Button("保存设置并退出") {
            dismiss()
            EventBus.shared.send(.settingsUpdated)
        }
    }
}
  1. HeaderViewModel订阅事件:
class HeaderViewModel: ObservableObject {
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        EventBus.shared.publisher()
            .filter { $0 == .settingsUpdated }
            .sink { [weak self] _ in
                self?.loadData()
            }
            .store(in: &cancellables)
    }
    
    func loadData() {
        // 数据加载逻辑
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 01:07:37