Bagaimana contoh status + pengikatan SwiftUI ini berhasil bekerja tanpa memanggil ulang body?
Seorang rekan kerja datang dengan contoh SwiftUI berikut yang sepertinya berfungsi seperti yang diharapkan (Anda dapat memasukkan beberapa teks dan akan dicerminkan di bawah), tetapi cara kerjanya mengejutkan saya!
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)
}
}
Model mental SwiftUI saya yang baru membuat saya berpikir bahwa mengetik di TextField akan mengubah $text
pengikatan, yang pada gilirannya akan mengubah text
var @State. Ini kemudian akan membatalkan ContentView
, memicu pemanggilan baru dari body
. Tapi yang menarik, bukan itu yang terjadi! Menyetel breakpoint di ContentView body
hanya mendapat satu kali, sedangkan WrappedText body
dijalankan setiap kali binding berubah. Namun, sejauh yang saya tahu, text
keadaan benar-benar sedang berubah.
Jadi, apa yang terjadi disini? Mengapa SwiftUI tidak memanggil kembali isi ContentView pada setiap perubahan text
?
Jawaban
On State mengubah mesin rendering SwiftUI pada awalnya memeriksa kesetaraan tampilan di dalam tubuh dan, jika beberapa di antaranya tidak sama, memanggil tubuh untuk membangun kembali, tetapi hanya tampilan yang tidak sama. Dalam kasus Anda, tidak ada tampilan yang bergantung (sebagai nilai) pada text
nilai (Binding seperti referensi - itu sama), jadi tidak ada yang perlu dibangun kembali pada level ini. Namun di WrappedText
dalamnya terdeteksi bahwa Text
dengan yang baru text
tidak sama dengan yang lama text
, sehingga tubuh WrappedText
dipanggil untuk merender ulang bagian ini.
Ini dinyatakan dalam pengoptimalan rendering SwiftUI - dengan memeriksa & memvalidasi tampilan yang benar-benar berubah berdasarkan kesetaraan.
Secara default, mekanisme ini bekerja dengan properti View struct, tetapi kita dapat terlibat di dalamnya dengan mengonfirmasi tampilan kita ke Eqatable
protokol dan menandainya sebagai .equatable()
pengubah untuk memberikan logika yang lebih rumit untuk mendeteksi apakah View harus (atau tidak) dirender ulang.