SwiftUI子视图间引用共享数据的其他方案及跨视图触发ViewModel方法
子视图间数据共享与跨ViewModel触发方法的替代方案
一、ObservableObject共享状态容器
创建一个遵循ObservableObject的全局共享状态类,将需要跨视图同步的状态放在其中,通过@EnvironmentObject或直接注入的方式让各视图共享实例,状态变化时自动触发响应。
实现示例:
- 定义共享状态类:
class AppState: ObservableObject { @Published var settingsChanged = false }
- 在App入口注入实例:
@main struct YourApp: App { @StateObject private var appState = AppState() var body: some Scene { WindowGroup { ContentView() .environmentObject(appState) } } }
- SettingsView中修改状态:
struct SettingsView: View { @EnvironmentObject var appState: AppState @Environment(\.dismiss) private var dismiss var body: some View { Button("保存设置并退出") { appState.settingsChanged = true dismiss() } } }
- 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的方法,逻辑直接清晰。
实现示例:
- SettingsView添加闭包:
struct SettingsView: View { @Environment(\.dismiss) private var dismiss var onDismiss: (() -> Void)? var body: some View { Button("保存设置并退出") { dismiss() onDismiss?() } } }
- 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通知中心
通过发送和接收系统通知实现跨组件通信,适合松散耦合的场景,注意监听需要及时销毁避免内存泄漏。
实现示例:
- 定义通知名称:
extension Notification.Name { static let settingsUpdated = Notification.Name("SettingsUpdated") }
- SettingsView发送通知:
struct SettingsView: View { @Environment(\.dismiss) private var dismiss var body: some View { Button("保存设置并退出") { dismiss() NotificationCenter.default.post(name: .settingsUpdated, object: nil) } } }
- 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传递类型化事件,比通知中心更安全,适合多事件类型的复杂场景。
实现示例:
- 定义事件总线:
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() } }
- SettingsView发送事件:
struct SettingsView: View { @Environment(\.dismiss) private var dismiss var body: some View { Button("保存设置并退出") { dismiss() EventBus.shared.send(.settingsUpdated) } } }
- 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
相关产品推荐
相关产品推荐

