@ObservedObject: что это, как работает и примеры

Автор: IT Sectr Опубликовано: 2026-06-19 Время чтения: 7 мин

@ObservedObject — это Property Wrapper в SwiftUI для наблюдения за экземпляром ObservableObject, переданным извне. В отличие от @StateObject, @ObservedObject не создаёт объект — он подписывается на изменения уже существующего. По данным Apple Developer Documentation (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, который требует реализации objectWillChange publisher. Когда любое свойство, помеченное @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Родительский компонент
Единственный экземплярДа, на весь lifecycleНет, может быть заменён
Пересоздание при рендереНет, сохраняетсяЗависит от родителя
Где использоватьКорневое view-владелецДочерние view

@StateObject гарантирует, что объект создаётся один раз и переживает повторные инициализации структуры view. @ObservedObject получает объект извне и пересоздаётся при каждой инициализации родительской структуры. Если родитель использует @StateObject для объекта, дочерние view могут безопасно применять @ObservedObject — объект будет един на всю иерархию.

Как @ObservedObject отслеживает изменения

Механизм отслеживания @ObservedObject базируется на Combine и протоколе ObservableObject. При инициализации SwiftUI вызывает objectWillChange publisher — объект должен испускать сигнал перед изменением @Published-свойства. Combine передаёт сигнал в dependency graph 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 Environment. Объект внедряется на уровне сцены или корневого view и автоматически доступен всем дочерним компонентам без явной передачи через инициализаторы. Внутри дочернего view @EnvironmentObject работает аналогично @ObservedObject, но получает объект из окружения.

Третий паттерн — композиция нескольких ObservableObject. В сложных приложениях view может наблюдать за несколькими объектами: @ObservedObject var user: UserService, @ObservedObject var network: NetworkMonitor. Это разделяет ответственность между сервисами и сохраняет testability каждого компонента.

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, который автоматически добавляет издателя к свойству внутри ObservableObject. Когда @Published-свойство изменяется, Combine генерирует событие через objectWillChange publisher. SwiftUI подписывается на этот publisher при использовании @ObservedObject или @StateObject и перерисовывает view при каждом новом значении.

@Published поддерживает все типы, включая опциональные, коллекции и пользовательские структуры. Однако для коллекций (массивы, словари) SwiftUI отслеживает только замену ссылки, а не изменение содержимого. Чтобы обнаружить добавление или удаление элемента, нужно переприсвоить коллекцию целиком либо использовать ObservableObject с manual objectWillChange.send().

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

Типичные ошибки с @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 Environment. @EnvironmentObject не требует явной передачи через конструкторы, но объект должен быть внедрён на верхнем уровне иерархии.

Как вручную уведомить SwiftUI об изменении ObservableObject?

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

Почему @ObservedObject не перерисовывает view при изменении внутри массива?

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

Можно ли использовать @ObservedObject в структуре, не реализующей View?

Нет, @ObservedObject — это SwiftUI Property Wrapper, доступный только внутри типов, реализующих протокол 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 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

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