Как этот пример SwiftUI binding + state работает без повторного вызова тела?
Сотрудник придумал следующий пример SwiftUI, который выглядит так, как будто он работает так, как ожидалось (вы можете ввести текст, и он будет отражен ниже), но то, как он работает, меня удивляет!
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)
}
}
Моя ментальная модель SwiftUI новичка заставила меня подумать, что ввод в TextField изменит $text
привязку, что, в свою очередь, text
изменит @State var. Это сделало бы недействительным ContentView
, запустив новый вызов body
. Но что интересно, этого не происходит! Установка точки останова в body
ContentView body
выполняется только один раз, а WrappedText запускается каждый раз при изменении привязки. И все же, насколько я могу судить, text
состояние действительно меняется.
Итак, что здесь происходит? Почему SwiftUI не вызывает повторно тело ContentView при каждом изменении text
?
Ответы
При изменении состояния механизм визуализации SwiftUI сначала проверяет равенство представлений внутри тела и, если некоторые из них не равны, вызывает тело для перестроения, но только эти неравные представления. В вашем случае ни одно представление не зависит (как значение) от text
значения (привязка похожа на ссылку - это то же самое), поэтому на этом уровне нечего перестраивать. Но внутри WrappedText
обнаруживается, что Text
with new text
не совпадает со старым text
, поэтому WrappedText
вызывается тело объекта для повторного рендеринга этой части.
Это объявленная оптимизация рендеринга SwiftUI - путем проверки и подтверждения точного измененного представления по равенству.
По умолчанию этот механизм работает с помощью свойств структуры представления, но мы можем участвовать в нем, подтвердив наше представление для Eqatable
протокола и пометив его .equatable()
модификатором, чтобы дать более сложную логику для определения того, следует ли (или нет) повторно отображать представление.