LazyVStack Инициализирует все представления при изменении SwiftUI.
У меня есть LazyVStack, который я хотел бы обновить только одно представление и не перезагружать все остальные на экране. В случае более сложных ячеек это приводит к значительному снижению производительности. Я включил образец кода
import SwiftUI
struct ContentView: View {
@State var items = [String]()
var body: some View {
ScrollView {
LazyVStack {
ForEach(self.items, id: \.self) { item in
Button {
if let index = self.items.firstIndex(where: {$0 == item}) {
self.items[index] = "changed \(index)"
}
} label: {
cell(text: item)
}
}
}
}
.onAppear {
for _ in 0...200 {
self.items.append(NSUUID().uuidString)
}
}
}
}
struct cell: View {
let text: String
init(text: String) {
self.text = text
print("init cell", text)
}
var body: some View {
Text(text)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Как вы можете видеть, даже при изменении только одной ячейки init вызывается для каждой ячейки. Есть ли способ избежать этого?
1 ответ
Вот рабочий код, есть несколько моментов, о которых стоит упомянуть. Представление в SwiftUI будет инициализировано тут и там или в любое время, когда SwiftUI сочтет это необходимым! Но тело представления будет вычислено, если действительно какое-то значение в теле изменится. Планируется так работать, есть и исключения. Как и тело вычисляется, даже значения, которые использовались в теле, были прежними без изменений, я не хочу вмешиваться в эту тему! Но в вашем примере и в вашей проблеме мы хотим, чтобы SwiftUI отображал только измененное представление, для этой цели код вниз работает без проблем, но, как вы можете видеть, я использовал VStack, если мы изменим
VStack
to , SwiftUI будет отображать дополнительное представление из-за своих скрытых кодов, и если вы прокрутите вниз, а затем вверх, он забудет все визуализированные представления и данные в памяти и попытается отобразить старые визуализированные представления, так что это природа , мы ничего не можем с этим поделать. Apple хочет быть ленивым. Но вы можете видеть, что
LazyVStack
не будет отображать все представления, но некоторые из них должны работать. мы не можем сказать или знать, сколько просмотров рендерится ленивым способом, но точно не все.
let initializingArray: () -> [String] = {
var items: [String] = [String]()
for _ in 0...200 { items.append(UUID().uuidString) }
return items
}
struct ContentView: View {
@State var items: [String] = initializingArray()
var body: some View {
ScrollView {
VStack {
ForEach(items, id: \.self) { item in
Button(action: {
if let index = self.items.firstIndex(where: { $0 == item }) {
items[index] = "changed \(index)"
}
}, label: {
ItemView(item: item)
})
}
}
}
}
}
struct ItemView: View {
let item: String
var body: some View {
print("Rendering row for:", item)
return Text(item)
}
}