I'm having trouble getting started in SwiftUI. What I want to do is rather simple at least I thought it would. What I want to do is that the ContentView expects a first and last name of a person. The button "Add to list" adds the person to a list and the second button shows a list of all added persons in a second view. I read about the property wrappers but I cannot get it to work. Do I need to change struct Person
to a class
in order to use the @ObservedObject
for initialising @StateObject var listOfPersons = [Person]()
or is there a more simpler Swift like way to pass the list to my PersonList View
?
My project code:
ContentView.swift
struct ContentView: View {
@State var firstName: String = ""
@State var lastName: String = ""
@StateObject var listOfPersons = [Person]()
var body: some View {
NavigationView {
ZStack (alignment: .top){
Color(.orange).opacity(0.2).edgesIgnoringSafeArea(.all)
VStack {
Text("Hello stranger")
.font(.title)
TextField("Fist name:", text: $firstName)
.padding()
TextField("Last name:", text: $firstName)
.padding()
HStack(spacing: 40) {
Button("Add to list") {
listOfPersons.append(Person(firstName: firstName, lastName: lastName))
}
.padding()
NavigationLink(destination: PersonList()) {
Text("Show list")
}
...
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
PersonList.swift
import SwiftUI
struct PersonList: View {
@Binding var listOfPersons = [Person]()
var body: some View {
Color(.orange).opacity(0.2).edgesIgnoringSafeArea(.all)
List(listOfPersons) { person in
PersonRow(person: person) }
}
}
struct PersonList_Previews: PreviewProvider {
static var previews: some View {
PersonList()
}
}
Person.swift
import Foundation
struct Person {
var firstName: String
var lastName: String
}
PersonRow.swift
import SwiftUI
struct PersonRow: View {
var person: Person
var body: some View {
Text("\(person.firstName), \(person.lastName)")
}
}
CodePudding user response:
Your code has a couple problems, but you're on the right track. First, replace @StateObject var listOfPersons = [Person]()
with:
@State var listOfPersons = [Person]()
@StateObject
is for an instance of a ObservableObject
class. @State
is what you should be using for a simple array of the Person
struct.
Then, in your current code, you're just instantiating a plain PersonList
without any parameters. You want to pass in listOfPersons
.
/// here!
NavigationLink(destination: PersonList(listOfPersons: $listOfPersons)) {
Text("Show list")
}
The $
sign gets the underlying Binding<[Person]>
from listOfPersons
, which means that any changes made inside PersonList
's listOfPersons
will be reflected back to ContentView
's listOfPersons
.
Finally, in PersonList
, change @Binding var listOfPersons = [Person]()
to
struct PersonList: View {
@Binding var listOfPersons: [Person]
...
}
@Binding
almost never needs to have a default value, since it's always passed in.