@StateObject e @ObservedObject ambos conectam um ObservableObject a uma visualização SwiftUI. A diferença-chave é a propriedade: use @StateObject quando o view cria o objeto e @ObservedObject quando o view recebe-o de outro lugar.

A escolha errada da embalagem pode causar sua model ser recriada sempre que SwiftUI reconstrói uma visualização. Eu cometi esse erro porque ambas as wrappers pareciam produzir o mesmo resultado inicialmente. A diferença só se torna visível quando seu view começa a possuir estado mutável.

@StateObject vs @ObservedObject

Você pode fazer a escolha correta respondendo uma pergunta: este view cria o objeto?

  • Use @StateObject quando o view cria e possui um ObservableObject.
  • Use @ObservedObject quando o view recebe um ObservableObject de um pai.
  • Nunca crie um objeto em linha usando @ObservedObject.
  • Não use @StateObject em múltiplas visualizações para a mesma instância.

Tanto as wrappers quanto os observadores desencadeiam atualizações de visualização quando uma propriedade @Published muda. No entanto, apenas @StateObject pede ao SwiftUI que preserve a vida útil do objeto para o view.

O que é um @ObservedObject?

A propriedade wrapper @ObservedObject observa um ObservableObject que outro view possui. Mudanças publicadas pelo objeto fazem com que o SwiftUI reavalie o view observador.

@MainActor
final class CounterViewModel: ObservableObject {
    @Published private(set) var count = 0

    func incrementCounter() {
        count += 1
    }
}

struct CounterView: View {
    @ObservedObject var viewModel: CounterViewModel

    var body: some View {
        VStack {
            Text("Count is: \(viewModel.count)")
            Button("Increment Counter") {
                viewModel.incrementCounter()
            }
        }
    }
}

CounterView recebe seu view model através de seu inicializador. Isso faz @ObservedObject a escolha correta, já que o view não controla a vida útil do objeto.