【问题标题】:LazyVStack Initializes all views when one changes SwiftUILazyVStack 在 SwiftUI 更改时初始化所有视图
【发布时间】:2022-01-23 02:55:06
【问题描述】:

我有一个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()
    }
}

正如您所见,即使只更改 1 个单元格,也会为每个单元格调用 init。有没有办法避免这种情况?

【问题讨论】:

  • 我尝试了您提供的代码,然后单击按钮,我看到初始化仅针对我单击的 1 个单元格运行。我使用部署目标 14.4 进行了测试

标签: ios swift swiftui lazyvstack


【解决方案1】:

这是一个工作代码,有几点要提一下,SwiftUI 中的 View 会在这里和那里或任何 SwiftUI 认为需要的时候初始化!但是,如果 body 中的某些值确实发生了变化,则 View 的 body 将被计算出来。它计划像那样工作,也有一些例外。就像 body 得到计算一样,即使在 body 中使用的值也和以前一样没有变化,我不想进入那个话题!但是在您的示例和您的问题中,我们希望 SwiftUI 仅呈现更改后的视图,为此,向下的代码可以正常工作,但是您可以看到我使用了 VStack,如果我们将 VStack 更改为 LazyVStack,SwiftUI由于它的隐藏代码,会渲染一些额外的视图,如果你向下滚动然后向上滚动,它会忘记内存中所有渲染的视图和数据,它会尝试渲染旧的渲染视图,所以这是 @987654323 的本质@,我们对此无能为力。苹果希望LazyVStack 变得懒惰。但是您可以看到LazyVStack 不会渲染所有视图,但其中一些需要工作。我们不能说或知道有多少视图以 Lazy 方式呈现,但肯定不是全部。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    相关资源
    最近更新 更多