如何将数组从一个视图传递到另一个视图并相应地更新视图

How to pass an array from a view to another and update the view accordingly

我的 View1 有一个列表、一个指向 View2 的导航按钮和一个基于数组中的项目的数组,它将生成行。

在 View2 中我有一个项目列表。

我希望用户转到 View2 并选择项目,然后将它们添加到现有的 View1 数组中。然后 View1 会更新为新添加的项目。

问题在于将项目从一个视图传递到另一个视图。如果在用户单击某个项目时 View2 返回到 View1 也会很棒。

这是我尝试创建的但不起作用:

查看 1

struct ContentView: View {

    @State private var newItems : Array = []

    var body: some View {
        NavigationView {
            List(){
                Section(header:
                    HStack{
                        Image(systemName: "plus.square.fill")
                        Text("Find Items")
                    })
                    {
                        NavigationLink( destination: MyListView(newItems: self.$newItems) ){
                                Text("Add Items")
                            }
                    }
                Section(header:
                    HStack{ Text("Items") }
                ) {
                    ForEach(newItems, id: \.self){ item in
                        Text("\(item)")
                    }
                }

            }
            .navigationBarTitle("Items List")
            .listStyle(GroupedListStyle())
        }
    }
}

查看 2

struct MyListView: View {
    @Binding var newItems: Array = []


    var myArray = [1, 2, 3, 4]

    var body: some View {
        List(myArray, id: \.self ){i in
            HStack{
                Image(systemName: "photo")
                Text("\(i)").font(.headline)
            }.onTapGesture {
                self.newItems.append(i)
                print(self.newItems.count)
            }
        }
    }
}

知道如何解决这个问题吗?

提前致谢

问题是你传递的是一个数组,它是一个值类型(数组、字符串、字典、结构等都是值类型)。当您传递该数组时,您(有效地)将其中数据的新副本传递给新视图。您在那里所做的更改不会影响您的第一个视图中的数组,然后必须传回旧视图,这对于保持同步有点混乱。

相反,您想使用引用类型(class),其中传递给新视图的变量实际上只是指向相同数据(class 实例)的指针第一个视图的变量指向。然后,当任何视图或函数作用于该变量时,它将编辑相同的实例数据。

通过多视图应用程序来回传递数据非常方便。

唯一的问题是您不能在 classes 上使用 @State 包装器。但是 classes 有一个相当简单的等价物。

您需要首先创建符合协议 ObservableObject 的 class,然后将其任何属性声明为 @Published。然后在您的视图中将 classes 实例化为 @ObservedObjects

因此,将您的新项目分解为 class

class NewItems: ObservableObject {
    @Published var items = [Int]()
    // And any other properties you want to pass back and forth.
    // Maybe even a complex Struct (which is a value type, but wrapped in a class)
}

然后在您的 ContentView 中,您必须实例化 class 并以不同的方式调用其 items 数组:

struct ContentView: View {
    @ObservedObject var newItems: NewItems() // New instance of NewItems is created.
    // FYI your array is now accessed by calling newItems.items like so:
    //  newItems.items = [1, 2, 3] 

 var body: some View {
            NavigationView {
                List(){
                    Section(header:
                        HStack{
                            Image(systemName: "plus.square.fill")
                            Text("Find Items")
                        })
                        {
                            // Now you're passing a pointer to the instance of the NewItems class
                            NavigationLink( destination: MyListView(newItems: self.$newItems) ){ 
                                    Text("Add Items")
                                }
                        }
                    Section(header:
                        HStack{ Text("Items") }
                    ) {
                        ForEach(newItems, id: \.self){ item in
                            Text("\(item)")
                        }
                    }

                }
                .navigationBarTitle("Items List")
                .listStyle(GroupedListStyle())
            }
        }
    }


所以您将 NewItems class 的一个实例传递给您的 MyListView,这意味着两个视图将在 NewItems 中共享相同的数据。一种观点的改变会影响另一种观点。来来回回,随心所欲,做出改变,它会奏效的。

以下是您如何处理 MyListView 中的新 class 实例:

struct MyListView: View {
    // We're getting a class now that has your [Int] within it
    @ObservedObject var newItems: NewItems


    var myArray = [1, 2, 3, 4]

    var body: some View {
        List(myArray, id: \.self ){i in
            HStack{
                Image(systemName: "photo")
                Text("\(i)").font(.headline)
            }.onTapGesture {
                self.newItems.append(i)
                // Make sure you call the items array within newItems
                print(self.newItems.items.count)
            }
        }
    }
}

要在多个视图(或多个函数等)之间共享相同的数据,您可以简单地将其包装在 class 中。然后将对该 class 实例中的相同数据进行任何视图的更改。

您甚至可以更进一步,用 @EnvironmentObject 包装 NewItems 实例,这样您甚至不必在 NavigationLink 的视图之间传递它.此处有更多详细信息:https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views

变化:

struct MyListView: View {
        @Binding var newItems: Array = [] 

收件人:

    struct MyListView: View {
        @Binding var newItems: Array

问题是在您的 MyListView 中,您将绑定数组替换为不同的本地空数组。

当您传入 @Binding 值时,您绝不会在目标视图中对其进行初始化!