首页 > 解决方案 > SwiftUI:创建一个类似于 List 但布局不同的视图

问题描述

编辑一些可用于重现问题的代码。(我真正的应用程序将在项目列表中包含数千个项目。

我正在开发一个使用 SwiftUI 的小型应用程序。我有一个依赖数据来重绘一些元素的视图,例如,

import SwiftUI

struct MyItem: Identifiable {
    var id: String = UUID().uuidString
    var name: String
    var yearsOfUse: Double
}

struct MyView: View {
    @Binding var aListOfItems: [MyItem]
    var body: some View {
            VStack(){
                ForEach(aListOfItems){item in
                    Text(item.name)
            }
        }
    }
}

struct ContentView: View {
    @State var items: [[MyItem]]
    @State var currentList: [MyItem]
    @State var currentListIndex: Int

    var body: some View {
        VStack(){
            Button(action: {
                if self.currentListIndex < self.items.count {
                    self.currentListIndex += 1
                    self.currentList = self.items[self.currentListIndex]
                }
            }){
                Text("Next")
            }.disabled(self.currentListIndex >= self.items.count - 1)
            Spacer()
            MyView(aListOfItems: $currentList)
            Spacer()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var items : [[MyItem]] = [[MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Pencil", yearsOfUse:1.0)],
                                     [MyItem(name:"CopyPaper", yearsOfUse:0.5), MyItem(name:"Pencil", yearsOfUse:1.0), MyItem(name:"BallPen", yearsOfUse:1.0)],
                                     [MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Rubbers", yearsOfUse:1.0)],
                                     [MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Siccer", yearsOfUse:2.0), MyItem(name:"Pencil", yearsOfUse:1.0)],
                                     [MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Pencil", yearsOfUse:1.0)]]

    static var currentItem = items[0]
    static var currentIndex = 0
    static var previews: some View {
        ContentView(items: items, currentList: currentItem, currentListIndex: currentIndex)
    }
}

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

        // Create the SwiftUI view that provides the window contents.
        let items : [[MyItem]] = [[MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Pencil", yearsOfUse:1.0)],
                                         [MyItem(name:"CopyPaper", yearsOfUse:0.5), MyItem(name:"Pencil", yearsOfUse:1.0), MyItem(name:"BallPen", yearsOfUse:1.0)],
                                         [MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Rubbers", yearsOfUse:1.0)],
                                         [MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Siccer", yearsOfUse:2.0), MyItem(name:"Pencil", yearsOfUse:1.0)],
                                         [MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Pencil", yearsOfUse:1.0)],
                                        [MyItem(name:"CopyPaper", yearsOfUse:0.5), MyItem(name:"Pencil", yearsOfUse:1.0), MyItem(name:"BallPen", yearsOfUse:1.0)],
                                        [MyItem(name:"Pen2", yearsOfUse:0.5), MyItem(name:"Rubbers", yearsOfUse:1.0)],
                                        [MyItem(name:"Pen3", yearsOfUse:0.5), MyItem(name:"Siccer1", yearsOfUse:2.0), MyItem(name:"Pencil", yearsOfUse:1.0)],
                                        [MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Pencil2", yearsOfUse:1.0)],
                                        [MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Siccer", yearsOfUse:2.0), MyItem(name:"Pencil", yearsOfUse:1.0)],
                                        [MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Pencil", yearsOfUse:1.0)],
                                        [MyItem(name:"CopyPaper", yearsOfUse:0.5), MyItem(name:"Pencil", yearsOfUse:1.0), MyItem(name:"BallPen", yearsOfUse:1.0)],
                                        [MyItem(name:"Pen2", yearsOfUse:0.5), MyItem(name:"Rubbers", yearsOfUse:1.0)],
                                        [MyItem(name:"Pen3", yearsOfUse:0.5), MyItem(name:"Siccer1", yearsOfUse:2.0), MyItem(name:"Pencil", yearsOfUse:1.0)],
                                        [MyItem(name:"Pen", yearsOfUse:0.5), MyItem(name:"Pencil2", yearsOfUse:1.0)]]

        let currentItem = items[0]
        let currentIndex = 0
        let contentView = ContentView(items: items, currentList: currentItem, currentListIndex: currentIndex)

        // Use a UIHostingController as window root view controller.
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }

MyView 是嵌入在内容视图中的视图,每次我单击内容视图上的按钮时,它都会更改可能包含各种元素的 aListOfItem 的值。例如,第一次单击时,aListOfItem 包含 5 个元素,第二次包含 7 个元素。当我在模拟器中测试时,我发现每次它都会根据元素计数创建新的文本视图。因此内存不断增加。

我想像 List 视图一样实现它,它可以重用之前创建的 Text 视图,因为我知道 aListOfItem 中元素的最大数量是 12。

非常感谢。

标签: listviewmemory-leaksswiftui

解决方案


推荐阅读