ObservableObject, StateObject e ObservedObject explicados como nunca antes!

João Pedro Barreto
Apple Developer Academy | UFPE
3 min readApr 20, 2023
Photo by Maxwell Nelson on Unsplash

No desenvolvimento iOS, nos deparamos com várias possibilidades de frameworks para desenvolvimento, o mais recente deles sendo a biblioteca SwiftUI, criada e sempre atualizada pela própria Apple.

E com certeza uma das coisas mais intrigantes e não tão convencional (nem intuitiva) de SwiftUI são os property wrappers.

Basicamente, como o nome já entrega, são indicadores de uma ou mais lógicas a serem aplicadas nos valores e varíaveis. E, pasmem, é realmente útil (é fácil de encontrar vários códigos com isso) quando se entende!

Dentre os mais utilizados, temos o State e Binding, que servem, especialmente, para váriaveis de tipos básicos: String, Int, Double e etc.

"E como a gente faz quando temos structs e classes?" Você pode perguntar…

SwiftUI tem property wrappers perfeitos para essas estruturas de dados.

1. StateObject

@StateObject deve ser utilizado quando queremos guardar e manipular informações de estado e não queremos que os valores dessa estrutura sejam perdidos quando trocamos de view.

class DataModel: ObservableObject {
var name = "Some Name"
var isEnabled = false
}

struct MyView: View {
@StateObject private var model = DataModel()

var body: some View {
Text(model.name)
}
}

2. ObservableObject

É um protocolo requerido para quando vamos usar @StateObject e outras propriedades de "compartilhamento". É o programador dizendo que aquela classe (só funciona em classes) e seus valores podem ser vistos por outras partes do código.

Certo, até agora só observamos, pegamos o valor da classe. Mas e se quisermos alterar esse valor?

class DataModel: ObservableObject {
@Published var name = "Some Name"
@Published var isEnabled = false
}

struct MyView: View {
@StateObject var model = DataModel()

var body: some View {
VStack {
Text(model.name)
Toggle("Enabled", isOn: $model.isEnabled)
.onChange(of: model.isEnabled) { isEnabled in
print ("O toggle está \(isEnabled)")
}
}
}
}

O que é o @Published?

Esse wrapper adiciona a propriedade de recarregar as views que usam a variável marcada como @Published. É como se ela gritasse para todas as views que usam essa variável: "Eu fui mudada!".

E esse $?

Precisamos adicionar esse prefixo para que Swift crie um Binding, ou seja, uma via de leitura-escrita com a variável em questão. Em outras palavras, para alterar os valores, precisamos do dollar sign prefix .

Testando esse código, você pode checar o console quando estiver clicando no toggle e verá que a mudança na propridade isEnabled está sendo alterada e comunicada pra todas as views.

Ta, mas é bastante comum em SwiftUI a componentização, ou seja, separar views (seja um botão usado em várias partes, ou no nosso caso, esse Toggle) em um arquivo dele mesmo, que depois so precisaria ser chamado com seus inicializadores. Para isso, vamos usar o…

3. ObservedObject

class DataModel: ObservableObject {
@Published var name = "Some Name"
@Published var isEnabled = false
}

struct MyView: View {
@StateObject var model = DataModel()

var body: some View {
VStack {
Text(model.name)
MySubView(model: model)
}
}
}

struct MySubView: View {
@ObservedObject var model: DataModel

var body: some View {
Toggle("Enabled", isOn: $model.isEnabled)
.onChange(of: model.isEnabled) { isEnabled in
print ("O toggle está \(isEnabled)")
}
}
}

Esse wrapper faz com que as propriedades marcadas com o @Published, quando alteradas, sejam "observadas" e atualizem a view de acordo.

Pronto :) Assim, qualquer view pode alterar os valores do objeto de estado e a tela saberá, podendo atualizar alguma imagem, interação ou fluxo.

Para esse artigo, me baseei fortemente na documentação da própria Apple. É um pouco mais técnico, mas vale a pena checar.

Espero que o bicho-papão que os property wrappers foram para mim tenha saído de baixo da cama de vocês!

--

--