Ответ
SwiftUI и Combine предлагают несколько паттернов для передачи данных, выбор зависит от степени связности и глубины иерархии.
1. @StateObject / @ObservedObject (Для связи родитель-ребенок)
Используется, когда владелец данных (родитель) передает их непосредственному потомку.
// Модель данных
class UserSettings: ObservableObject {
@Published var username = ""
}
// Родительский View создает и владеет объектом
struct ParentView: View {
@StateObject var settings = UserSettings() // Владение
var body: some View {
ChildView(settings: settings) // Передача
}
}
// Дочерний View наблюдает за объектом
struct ChildView: View {
@ObservedObject var settings: UserSettings // Наблюдение
var body: some View {
TextField("Name", text: $settings.username)
}
}
2. @EnvironmentObject (Для глубокой иерархии)
Позволяет передавать данные через множество уровней без явной передачи каждому View.
// В корне приложения (или сцены) помещаем объект в окружение
@main
struct MyApp: App {
@StateObject var settings = UserSettings()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(settings) // Инъекция
}
}
}
// Любой View в иерархии может получить доступ
struct DeepChildView: View {
@EnvironmentObject var settings: UserSettings // Получение
var body: some View {
Text(settings.username)
}
}
3. Прямая передача через Combine Publisher
Подходит для более реактивных или одноразовых событий.
// В одном модуле
class EventService {
static let shared = EventService()
private init() {}
let userDidLogin = PassthroughSubject<String, Never>()
}
// Отправка события
EventService.shared.userDidLogin.send("NewUser")
// Подписка в другом модуле
EventService.shared.userDidLogin
.sink { userName in
print("User (userName) logged in")
}
.store(in: &cancellables)
Рекомендация: Для сложных приложений рассмотрите архитектурные подходы (MVVM, Redux) с централизованным хранилищем состояния.