SwiftUI Série 04|Gerenciamento de estado SwiftUI: seleção de @State, @Binding, @ObservedObject, @StateObject
A verdadeira chave é responder primeiro "Quem possui esses dados e quem conduz as mudanças na interface?"
O lugar onde as pessoas têm maior probabilidade de ficar “presas” no SwiftUI é o estado.
As perguntas mais comuns geralmente são estas:
- Devemos usar
@Stateou@Bindingpara este valor? - ViewModel será inicializado repetidamente
- Por que a subvisão não pode alterar os dados da visão pai?
- O valor obviamente mudou, mas a página não foi atualizada conforme o esperado.
Se você confiar apenas na memorização de wrappers de atributos para esses problemas, será fácil ficar cada vez mais confuso. Porque a verdadeira causa raiz geralmente é:
Sem primeiro pensar claramente sobre “quem é o dono deste estado?”
1. Não se apresse em escolher uma embalagem. Primeiro pergunte: de quem são os dados?
Esta é a questão mais importante.
No SwiftUI, sempre que você vir um valor de estado, pergunte-se:
- Este valor pertence à Visualização atual?
- A visão pai ainda a possui e a subvisão é apenas emprestada e modificada.
- Ainda pertencente a um objeto externo, a View atual está apenas observando
Uma vez que esta pergunta seja respondida claramente, muitas escolhas de wrapper surgirão naturalmente. Pelo contrário, se você pular esta etapa e perguntar diretamente “qual deles é comumente usado neste cenário”, será fácil acumular código por tentativa e erro.
2. @State é realmente adequado para “o próprio estado local da visualização atual”
@State é mais adequado para:
Este estado pertence apenas à Visualização atual. A existência local, o consumo local e o abandono desta visão são basicamente sem sentido.
Por exemplo:
- O conteúdo atual da caixa de entrada
- Se deseja exibir a planilha
- Um certo estado parcialmente expandido e recolhido
- Seleção de guia atual
O que esses estados têm em comum é:
- Propriedade clara
- O ciclo de vida está fortemente ligado a esta Visão
- Não vale a pena atualizar para o status de negócio externo
Se uma parte do estado não fizer sentido fora da Visualização atual, geralmente é uma boa opção para @State.
3. O ponto principal do @Binding é que “a propriedade não mudou, mas a permissão de gravação foi emprestada”
Uma situação comum é entender @Binding como “as subvisualizações também podem alterar o valor da visualização pai”.
Esse entendimento não está errado, mas não é suficientemente preciso.
E mais:
- Este estado ainda pertence à visualização pai
- a subvisão não a possui
- A subvisão obtém apenas os canais de leitura e gravação
Esta questão é crítica porque determina se a atribuição correta dos dados é mantida quando o componente é pontuado.
Quer dizer:
@Stateé “meu”@Bindingé “ainda o mesmo, mas estou autorizado a alterá-lo”
Uma vez entendido em termos de propriedade, o @Binding não pode mais ser confundido com uma “solução única de compartilhamento de dados”.
4. @ObservedObject e @StateObject são mais facilmente confundidos porque as pessoas costumam misturar “observação” e “posse”
O uso indevido mais comum desses dois wrappers vem essencialmente do mesmo problema:
Não está claro se “a Visualização atual observa um objeto externo” ou “a Visualização atual cria e mantém este objeto de forma estável”.
@ObservedObject
É melhor expressar:
- Este objeto é passado de fora
- A visão atual apenas observa
- A Visualização atual não é responsável por criá-la, nem por mantê-la estável
@StateObject
É melhor expressar:
- A View atual cria ela mesma este objeto
- e deseja mantê-lo estável durante a atualização do View
A diferença fundamental entre os dois não é “qual deles está mais avançado”, mas sim:
- quem criou o objeto
- Quem é responsável pelo ciclo de vida do objeto
Isso também mostra que muitos problemas de inicialização repetida do ViewModel são essencialmente propriedade de objeto mal colocada.
5. Um julgamento de engenharia muito prático: o status da UI local e o status do negócio devem ser considerados separadamente
O status de muitas páginas será confuso e o status de diferentes níveis será agrupado em uma bola.
Por exemplo, uma página pode conter:
- Conteúdo da caixa de entrada
- Filtre se a janela pop-up está aberta
- Resultados da solicitação de rede
- Estado de carregamento da página
- Lista de objetos de negócios
Esses valores parecem ser chamados de “estado”, mas não são o mesmo tipo de estado.
Eu normalmente o divido em duas categorias:
1. Estado da IU local
Por exemplo:
- Se deve expandir
- Conteúdo de entrada atual
- Item atualmente selecionado
- Interruptor de exibição parcial
Este tipo de status está mais próximo de @State / @Binding.
2. Status dos dados comerciais
Por exemplo:
- Informações do usuário
- Listar dados
- Processo de carregamento
- Erro de solicitação
Esse tipo de estado geralmente é melhor colocado em um objeto observável externo ou em um contêiner de estado de nível superior.
Uma vez que esses dois tipos de estados não sejam diferenciados, a página terá facilmente o estado local, o estado do ViewModel e os valores de passagem da camada pai. No final, não está claro quem é o dono.
6. Muitos problemas de “o valor mudou, mas a interface está errada” são essencialmente causados pela mistura dos limites do estado.
Uma situação comum é que:
- Obviamente mudei o valor, mas por que a página não mudou como eu pensava?
É claro que às vezes esse é o wrapper errado, mas com mais frequência:
- O estado que deveria pertencer à camada pai é mantido temporariamente pela camada filho.
- Objetos que deveriam existir há muito tempo são tratados como objetos de observação temporários.
- O status da UI local e o status comercial se sobrepõem
Em outras palavras, o que parece ser um “problema de atualização” geralmente é, na verdade, um problema de propriedade.
Para muitos problemas de status no SwiftUI, depois de verificar “quem possui esses dados”, geralmente você pode encontrar a causa raiz mais rápido do que observar o fenômeno da interface.
7. Um método de julgamento simplificado que uso com frequência
Embora os projetos reais sejam mais complicados, costumo usar este conjunto de julgamentos simples no desenvolvimento diário:
1. Este é o estado simples da própria visualização atual?
Sim, dê prioridade a @State
2. Isso pertence à visão pai e foi emprestado e modificado pela subvisão atual?
Sim, dê prioridade a @Binding
3. Este é um objeto observável transmitido de fora?
Sim, dê prioridade a @ObservedObject
4. Este é um objeto que a View atual criou e espera manter estável?
Sim, dê prioridade a @StateObject
Este conjunto de julgamentos certamente não cobre todos os detalhes, mas é bastante prático para um grande número de páginas de negócios.
8. Conclusão: O que realmente precisamos entender primeiro sobre a gestão estatal é a propriedade.
Para resumir, eu diria:
No SwiftUI, a coisa mais importante sobre o gerenciamento de estado é primeiro perguntar “Quem possui esses dados e quem é responsável por fazer a interface mudar com eles.”
Depois que a propriedade estiver clara primeiro, muitas opções de embalagem surgirão naturalmente. Por outro lado, se você não pensar claramente sobre a propriedade e se familiarizar com a API posteriormente, será fácil escrever uma página que “roda, mas fica cada vez mais confusa”.
What to read next
Want more posts about SwiftUI?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to keep following #iOS?
Tags are useful for related tools, specific problems, and similar troubleshooting notes.
View same tagWant to explore another direction?
If you are not sure what to read next, return to the homepage and start from categories, topics, or latest updates.
Back home