Eu uso a nova @Observable
macro para meu ViewModel. A classe se parece com isso
@Observable
class TransitiveModel {
private var strings: [String] = []
func getStrings() -> [String] {
return strings
}
func addString(_ item: String) {
strings.append(item)
}
}
Esta é uma simplificação da minha classe real, mas serve como um exemplo mínimo. Você poderia argumentar que neste exemplo um método getStrings() pode não ser necessário, no entanto, na minha classe real eu passo parâmetros e faço alguns cálculos antes, então, por favor, finja que é importante.
Eu tenho uma visão simples
private var model = TransitiveModel()
var body: some View {
VStack {
ForEach(model.getStrings(), id: \.self) { item in
Text(item)
}
Button("Add Item") {
model.addString("Hello")
}
}
}
Quando eu pressiono o botão, eu esperava que nada mudasse visualmente, porque eu não estou diretamente inscrito no strings
-array na View. No entanto, eu observei que a View será atualizada de qualquer maneira, provavelmente porque getStrings()
depende do array, que foi alterado. Eu não quero confiar nesse comportamento a menos que eu tenha certeza de que ele está correto e não é uma falha ou algo assim. Estou certo em pensar que a mudança em strings
acionará a função para ser chamada novamente? E há algum tipo de documentação que me ajudará a entender isso?
O SwiftUI ainda pode encontrar dependências de visualizações mesmo se você não acessar "diretamente" uma
@Observable
propriedade. Desde que o getter/setter de uma@Observable
propriedade seja chamado durante a execução deView.body
, essa propriedade será encontrada como uma dependência dessa visualização.Isso ocorre porque a
@Observable
macro gera código extra no getter/setter dessas propriedades para registrar acessos/mutações dessas propriedades em um registrador de observação, que o SwiftUI usa para rastrear dependências.Este código gerado não olha para a pilha de chamadas e diz "isso não é chamado diretamente de,
View.body
então não registrarei este acesso". Afinal, o Observation não deve ser fortemente acoplado ao SwiftUI. E por que ele faria esse trabalho extra quando o oposto é tipicamente mais desejável?Para documentação, de cabeça, posso pensar nos dois vídeos da WWDC, Discover Observation in SwiftUI , onde eles explicam como o Observation funciona, e Demystifying SwiftUI , onde eles falam sobre o que é uma "dependência" de uma visualização.
Quanto à pergunta nos comentários:
Sim. Como o getter de
strings
é chamado embody
, a visualização SwiftUI será atualizada sempre que o setter destrings
for chamado, de qualquer lugar.Se você não quiser que a visualização mude visualmente quando
models.strings
mudar por algum motivo, você pode adicionar um extra@State
para armazenar separadamente as strings. Isso@State
será independente demodel.strings
.