@ObservedObject: що це, як працює та приклади

Автор: IT Sectr Опубліковано: 2026-06-19 Час читання: 7 хв

@ObservedObject — це Property Wrapper у SwiftUI для спостереження за екземпляром ObservableObject, переданим ззовні. На відміну від @StateObject, @ObservedObject не створює об'єкт — він підписується на зміни вже існуючого. Згідно з Документацією Apple для розробників (2025), @ObservedObject використовується в дочірніх view, яким потрібно відстежувати дані, що належать батьківському елементу. @ObservedObject забезпечує реактивний зв'язок без керування життєвим циклом об'єкта.

Головне

  • @ObservedObject — Property Wrapper для спостереження за ObservableObject без володіння
  • Без створення — об'єкт передається з батьківського view або середовища
  • @Published — властивості всередині ObservableObject, зміни яких відстежує SwiftUI
  • Перемалювання — при зміні властивості @Published SwiftUI оновлює всі підписані view
  • Не плутати з @StateObject — @ObservedObject не гарантує єдиний екземпляр

Що таке @ObservedObject у SwiftUI?

@ObservedObject — це Property Wrapper, який підписує view на зміни ObservableObject. ObservableObject — це протокол із фреймворку Combine, який вимагає реалізації publisher objectWillChange. Коли будь-яка властивість, позначена @Published, змінюється всередині ObservedObject, publisher надсилає сигнал, і SwiftUI перемальовує всі view, підписані через @ObservedObject.

Головна характеристика @ObservedObject — відсутність володіння. View не відповідає за створення або знищення об'єкта. Об'єкт створюється в батьківському view (через @StateObject) або впроваджується через @EnvironmentObject. Дочірнє view лише спостерігає за змінами та отримує оновлення. Якщо об'єкт буде замінено в батьківському елементі, @ObservedObject переключиться на новий екземпляр.

@ObservedObject підходить для сценаріїв спільного використання даних: модель користувача, спільні налаштування, стан підключення до сервера. Коли кілька view на різних рівнях ієрархії повинні відображати одні й ті самі дані, @ObservedObject у кожному view створює незалежні, але узгоджені підписки на одне джерело.

@ObservedObject vs @StateObject: ключові відмінності

Різниця між @ObservedObject і @StateObject — одна з найпоширеніших тем на співбесідах із SwiftUI. Основне правило: @StateObject створює та володіє об'єктом, @ObservedObject спостерігає за вже існуючим. Порушення цього правила призводить до неочікуваної втрати даних або подвійної ініціалізації.

Характеристика@StateObject@ObservedObject
Створення об'єктаТак, при ініціалізації viewНі, отримує готовий
ВолодінняПоточний viewБатьківський компонент
Єдиний екземплярТак, на весь життєвий циклНі, може бути замінений
Перестворення при рендеріНі, зберігаєтьсяЗалежить від батька
Де використовуватиКореневий view-власникДочірні view

@StateObject гарантує, що об'єкт створюється один раз і переживає повторні ініціалізації структури view. @ObservedObject отримує об'єкт ззовні та перестворюється при кожній ініціалізації батьківської структури. Якщо батько використовує @StateObject для об'єкта, дочірні view можуть безпечно застосовувати @ObservedObject — об'єкт буде єдиним у всій ієрархії.

Як @ObservedObject відстежує зміни

Механізм відстеження @ObservedObject базується на Combine і протоколі ObservableObject. Під час ініціалізації SwiftUI викликає publisher objectWillChange — об'єкт повинен випромінювати сигнал перед зміною властивості @Published. Combine передає сигнал у граф залежностей SwiftUI, який позначає всі залежні view як такі, що потребують оновлення. Це відбувається синхронно перед зміною значення.

swift
class WeatherService: ObservableObject {
    @Published var temperature: Double = 22.0
    @Published var city: String = "Moscow"
}

struct WeatherView: View {
    @ObservedObject var weather: WeatherService

    var body: some View {
        VStack {
            Text("\(weather.city)")
            Text("\(weather.temperature)°C")
        }
    }
}

У лістингу WeatherService — ObservableObject із двома властивостями @Published. WeatherView оголошує @ObservedObject var weather: WeatherService, отримуючи екземпляр від батька. Коли temperature змінюється, objectWillChange спрацьовує до встановлення нового значення, SwiftUI перемальовує WeatherView і відображається актуальна температура. Підписка автоматично керується SwiftUI — розробнику не потрібно викликати sink або dispose.

Патерни використання @ObservedObject

Перший патерн — передача моделі через ініціалізатор. Батько створює ObservableObject через @StateObject і передає його дочірнім view як @ObservedObject. Це стандартна ієрархічна передача даних, при якій кореневий view керує життєвим циклом моделі, а всі вкладені компоненти підписуються на зміни.

Другий патерн — EnvironmentObject, глобальна версія @ObservedObject через середовище SwiftUI. Об'єкт впроваджується на рівні сцени або кореневого view і автоматично доступний усім дочірнім компонентам без явної передачі через ініціалізатори. Всередині дочірнього view @EnvironmentObject працює аналогічно @ObservedObject, але отримує об'єкт із середовища.

Третій патерн — композиція кількох ObservableObject. У складних застосунках view може спостерігати за кількома об'єктами: @ObservedObject var user: UserService, @ObservedObject var network: NetworkMonitor. Це розділяє відповідальність між сервісами та зберігає тестованість кожного компонента.

swift
struct DashboardView: View {
    @ObservedObject var user: UserViewModel
    @ObservedObject var network: NetworkMonitor

    var body: some View {
        VStack {
            Text("Welcome, \(user.name)")
            HStack {
                Circle()
                    .fill(network.isConnected ? Color.green : Color.red)
                    .frame(width: 10, height: 10)
            }
        }
    }
}

DashboardView спостерігає за UserViewModel і NetworkMonitor. Кожен об'єкт відповідає за свою область даних і незалежно повідомляє view про зміни. Якщо мережа відключається, NetworkMonitor змінює isConnected, і SwiftUI перемальовує DashboardView, оновлюючи колір індикатора. Композиція ObservableObject — кращий спосіб організації даних у SwiftUI-застосунках.

@Published: зв'язок між ObservableObject і SwiftUI

@Published — це Property Wrapper із Combine, який автоматично додає publisher до властивості всередині ObservableObject. Коли властивість @Published змінюється, Combine генерує подію через publisher objectWillChange. SwiftUI підписується на цей publisher при використанні @ObservedObject або @StateObject та перемальовує view при кожному новому значенні.

@Published підтримує всі типи, включаючи опціональні, колекції та користувацькі структури. Однак для колекцій (масиви, словники) SwiftUI відстежує лише заміну посилання, а не зміну вмісту. Щоб виявити додавання або видалення елемента, потрібно перепризначити колекцію повністю або використовувати ObservableObject із ручним objectWillChange.send().

Важлива деталь: @Published має використовуватися лише всередині класу, що реалізує ObservableObject. Використання @Published поза ObservableObject викличе помилку компіляції. Також @Published не можна застосовувати до властивостей лінивої ініціалізації (lazy var) або обчислюваних властивостей.

Типові помилки з @ObservedObject

Найкритичніша помилка — використання @ObservedObject для створення об'єкта. Якщо написати @ObservedObject var model = UserViewModel() у батьківському view, при кожному рендері створюватиметься новий екземпляр UserViewModel. Дані будуть втрачені, а підписки @Published перестворені. Завжди використовуйте @StateObject для створення та @ObservedObject лише для отримання готового об'єкта.

Друга помилка — зміна властивостей @Published поза головним потоком. ObservableObject використовує Combine, який вимагає надсилання змін на головному потоці (main actor). Якщо змінити @Published у фоновій черзі, SwiftUI може перемалювати view у невідповідний момент, викликаючи race conditions. Використовуйте DispatchQueue.main.async або @MainActor для оновлення.

Третя проблема — циклічні оновлення. Якщо зміна @Published включає побічні ефекти, які знову змінюють @Published, виникає нескінченний цикл перемалювань. Рішення: використовувати прапорці-захисники (isUpdating) або розносити логіку на різні ObservableObject із чіткими межами відповідальності.

Часті запитання

Чи може @ObservedObject бути опціональним?

Так, SwiftUI підтримує @ObservedObject var model: UserViewModel?. Однак view не буде підписаний на зміни, поки об'єкт nil. При присвоєнні значення підписка активується автоматично.

Чим @ObservedObject відрізняється від @EnvironmentObject?

@ObservedObject отримує об'єкт через ініціалізатор, @EnvironmentObject — через середовище SwiftUI. @EnvironmentObject не вимагає явної передачі через конструктори, але об'єкт має бути впроваджений на верхньому рівні ієрархії.

Як вручну повідомити SwiftUI про зміну ObservableObject?

Викличте objectWillChange.send() до зміни властивості. Це корисно, якщо @Published не підходить (наприклад, для обчислюваних властивостей або операцій із колекціями, де потрібно повідомити про зміну до мутації).

Чому @ObservedObject не перемальовує view при зміні всередині масиву?

@ObservedObject і @Published відстежують заміну посилання, а не мутацію вмісту колекції. Для перемалювання потрібно перепризначити масив: items.append(newItem) → items = items або використовувати objectWillChange.send() перед мутацією.

Чи можна використовувати @ObservedObject у структурі, що не реалізує View?

Ні, @ObservedObject — це Property Wrapper SwiftUI, доступний лише всередині типів, що реалізують протокол View. Для звичайних структур використовуйте Combine безпосередньо з ObservableObjectPublisher.

Підсумки

  • @ObservedObject — Property Wrapper для спостереження за ObservableObject без володіння
  • @StateObject — створює об'єкт, @ObservedObject — спостерігає за існуючим
  • @Published — автоматичний publisher для властивостей ObservableObject
  • Підписка — SwiftUI автоматично керує підпискою Combine при використанні @ObservedObject
  • Композиція — view може спостерігати за кількома ObservableObject одночасно
  • Main actor — властивості @Published слід змінювати лише на головному потоці
  • EnvironmentObject — альтернатива @ObservedObject для неявної передачі через середовище

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також