Comment cet exemple de liaison SwiftUI + état parvient-il à fonctionner sans ré-invoquer le corps?

Aug 19 2020

Un collègue de travail est venu avec l'exemple suivant SwiftUI qui ressemble comme il fonctionne exactement comme prévu (vous pouvez entrer un texte et il devient miroir ci - dessous), mais la façon dont cela fonctionne est surprenant pour moi!

import SwiftUI

struct ContentView: View {
    @State var text = ""
    var body: some View {
        VStack {
            TextField("Change the string", text: $text) WrappedText(text: $text)
        }
    }
}

struct WrappedText: View {
    @Binding var text: String
    var body: some View {
        Text(text)
    }
}

Mon modèle mental novice de SwiftUI m'a amené à penser que taper dans TextField changerait la $textliaison, ce qui à son tour textmuterait la variable @State. Cela invaliderait alors le ContentView, déclenchant une nouvelle invocation de body. Mais curieusement, ce n'est pas ce qui se passe! La définition d'un point d'arrêt dans ContentView bodyn'est frappée qu'une seule fois, tandis que WrappedText bodyest exécuté à chaque fois que la liaison change. Et pourtant, pour autant que je sache, l' textétat est vraiment en train de changer.

Alors, que se passe-t-il ici? Pourquoi SwiftUI ne ré-appelle-t-il pas le corps de ContentView à chaque modification de text?

Réponses

1 Asperi Aug 20 2020 at 04:04

Lors du changement d'état, le moteur de rendu SwiftUI vérifie d'abord l'égalité des vues à l'intérieur du corps et, si certaines d'entre elles ne sont pas égales, appelle le corps à reconstruire, mais uniquement les vues non égales. Dans votre cas, aucune vue ne dépend (en tant que valeur) de la textvaleur (la liaison est comme une référence - c'est la même chose), donc rien à reconstruire à ce niveau. Mais à l'intérieur, WrappedTexton détecte que Textavec nouveau textn'est pas égal à un avec ancien text, donc body of WrappedTextest appelé à restituer cette partie.

Ceci est déclaré optimisation du rendu de SwiftUI - en vérifiant et en validant la vue modifiée exacte par égalité.

Par défaut, ce mécanisme fonctionne avec les propriétés de structure de View, mais nous pouvons y être impliqués en confirmant notre vue sur le Eqatableprotocole et en le marquant comme .equatable()modificateur pour donner une logique plus compliquée pour détecter si View doit (ou non) être restitué.