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

时间:2020-05-17 15:46:00

标签: arrays swift swiftui swiftui-list swiftui-navigationlink

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

有什么办法解决这个问题吗?

预先感谢

2 个答案:

答案 0 :(得分:2)

更改:

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

收件人:

    struct MyListView: View {
        @Binding var newItems: Array

问题在于,在MyListView中,您将绑定数组替换为其他本地空数组。

传递@Binding值时,切勿在目标视图中初始化它!

答案 1 :(得分:0)

问题是您要传递一个数组,该数组是一种值类型(数组,字符串,字典,结构等是值类型)。当您传递该数组时,您(正在有效地)将其中的数据新副本传递给新视图。您在那里进行的更改不会影响您的第一个View中的数组,因此必须将其传递回旧的View中,以保持同步有点混乱。

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

超级方便,可通过多视图应用程序来回传递数据。 ?

唯一要注意的是,您不能在类上使用@State包装器。但是类有一个相当简单的等效项。

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

所以将您的newItems分成一个类

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中,必须实例化该类并以不同的方式调用其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类的实例传递给MyListView,这意味着两个视图都将在该NewItems中共享相同的数据。一个视图中的更改将影响另一个视图。来回移动所有所需的内容,进行更改,它就可以正常工作。

这是在MyListView中处理新类实例的方式:

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

要在多个视图(或多个函数等)之间共享相同的数据,只需将其包装在一个类中即可。然后,将对该类实例中的相同数据进行任何视图更改。

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