In che modo questo esempio di associazione + stato SwiftUI riesce a funzionare senza richiamare nuovamente il corpo?

Aug 19 2020

Un collega ha escogitato il seguente esempio SwiftUI che sembra funzionare proprio come previsto (puoi inserire del testo e viene rispecchiato di seguito), ma il modo in cui funziona è sorprendente per me!

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)
    }
}

Il mio modello mentale da principiante di SwiftUI mi ha portato a pensare che digitando nel TextField cambierebbe l' $textassociazione, che a sua volta avrebbe mutato la text@State var. Ciò quindi invaliderebbe il ContentView, innescando una nuova invocazione di body. Ma è interessante notare che non è quello che succede! L'impostazione di un punto di interruzione in ContentView bodyviene raggiunta solo una volta, mentre WrappedText bodyviene eseguita ogni volta che l'associazione cambia. Eppure, per quanto ne so, lo textstato sta davvero cambiando.

Allora, cosa sta succedendo qui? Perché SwiftUI non richiama nuovamente il corpo di ContentView ad ogni modifica a text?

Risposte

1 Asperi Aug 20 2020 at 04:04

Al cambio di stato, il motore di rendering SwiftUI controlla inizialmente l'uguaglianza delle viste all'interno del corpo e, se alcune di esse non sono uguali, chiama body per ricostruire, ma solo quelle viste non uguali. Nel tuo caso nessuna vista dipende (come valore) dal textvalore (il legame è come un riferimento - è lo stesso), quindi niente da ricostruire a questo livello. Ma all'interno WrappedTextsi rileva che Textcon nuovo textnon è uguale a uno con vecchio text, quindi body of WrappedTextè chiamato a ri-renderizzare questa parte.

Questa è dichiarata ottimizzazione del rendering di SwiftUI, controllando e convalidando la visualizzazione esatta modificata per uguaglianza.

Per impostazione predefinita, questo meccanismo funziona con le proprietà della struttura della vista, ma possiamo essere coinvolti confermando la nostra vista sul Eqatableprotocollo e contrassegnandola come .equatable()modificatore per fornire una logica più complicata per rilevare se View debba essere (o non essere) ri-renderizzato.