How to create an instance of my class?

I'm trying to create a new instance of my class "people" and add it to my list called listOfPeople. At the start, I ask how many people am I going to add. After I answer that, I add 1 to the variable "level" so I can continue as if it where a for loop. Now at level 1, I add the name and numberAssigned to the new instance which would supposedly go in listOfPeople in the position in which the variable counter is on. After I click the button with text "Add name" I would add another name and so on until I reach the numberOfpeople, so again, trying to simulate a for loop (I'm aware I have not added the logic for the textfield and button to add a new instance and stop when counter reaches the numberOfpeople). However, in this case, after I add the persons name and numberAssigned, it gives me the error in image number three. Which says "Thread 1: Fatal error: Index out of range."

How could I make this work? I learned how to do this in c++ but I clearly do not know how to accomplish it in swiftui. Any help is appreciated! ;)

I could make it work this way, the only problem is that if the user wants to add 1,000 people, I would have to have 1,000 variables pre-created, which I do not want, I want to be able to do it as a for-loop per se.

Accepted Reply

Please, when you post code, post the code as text not images. And use code formatter tool.

struct ContentView: View {
    class People { // Uppercase name
        var name = ""
        var numberAsigned = 0
    }
    @State var level = 0
    @State var numberOfpeople = 0
    @State var name = ""
    @State var counter = 0
    @State var assigned = 0
    /*
     var person1 = people()
     var person2 = people()
     var person3 = people()
     var person4 = people()
     var person5 = people()
     var person6 = people()
     */
    
    var body: some View {
        var listOfPeople: [People] = []
        
        if level == 0 {
            VStack {
                TextField("How many people", value: $numberOfpeople, format: .number)
                    .frame (width: 100, height: 100)
                ZStack {
                    Rectangle()
                        .frame (width: 100, height: 100)
                        .cornerRadius(25)
                    Button(action: { level += 1 },
                           label: { Text("Add")
                            .foregroundColor(Color.white)
                    })
                }
            }
        } else if level == 1 {
            VStack {
                TextField ("Name of person", text: $name)
                TextField( "Number assigned", value: $assigned, format: .number)
                Button(action: {
                    listOfPeople[counter].name = name
                    listOfPeople[counter].numberAsigned = assigned
                    counter += 1
                }, label: {
                    Text ("Add Name")
                })
            }
        }
    }
}

Note also that class names should start with Uppercase (People)

You never append People to listOfPeople, which is declared as:

        var listOfPeople: [People] = []

Hence it is always empty and crashes when you try to access an element.

Then, listOfPeople should be a State var, otherwise it is reinitialized each time you redraw the view.

This works better:

struct ContentView: View {
    class People { // Uppercase name
        var name = ""
        var numberAsigned = 0  / probably a typo: numberAssigned
    }
    @State var level = 0
    @State var numberOfpeople = 0
    @State var name = ""
    @State var counter = 0
    @State var assigned = 0
    @State var listOfPeople: [People] = []
    
    var body: some View {
        
        if level == 0 {
            VStack {
                TextField("How many people", value: $numberOfpeople, format: .number)
                    .frame (width: 300, height: 100)
                ZStack {
                    Rectangle()
                        .frame (width: 100, height: 100)
                        .cornerRadius(25)
                    Button(action: { level += 1
                        for _ in 0..<numberOfpeople {
                            listOfPeople.append(People())
                        }
                    },
                           label: { Text("Add")
                            .foregroundColor(Color.white)
                    })
                }
            }
        } else if level == 1 {
            VStack {
                TextField ("Name of person", text: $name)
                TextField( "Number assigned", value: $assigned, format: .number)
                Button(action: {
                    listOfPeople[counter].name = name
                    listOfPeople[counter].numberAsigned = assigned
                    counter += 1
                }, label: {
                    Text ("Add Name")
                })
            }
        }
    }
}

Now you have to make your code more robust (disable button when completed), improve readability with labels for TextFields…

struct ContentView: View {
    class People { // Uppercase name
        var name = ""
        var numberAsigned = 0
    }
    @State var level = 0
    @State var numberOfpeople = 0
    @State var name = ""
    @State var counter = 0
    @State var assigned = 0
    @State var listOfPeople: [People] = []
    
    var body: some View {
        
        if level == 0 {
            VStack {
                HStack {
                    Text("How many people")
                        .frame (width: 150, height: 20, alignment: .trailing)
                    TextField("", value: $numberOfpeople, format: .number)
                        .frame (width: 50, height: 20, alignment: .leading)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                }
                ZStack {
                    Rectangle()
                        .frame(width: 100, height: 100)
                        .cornerRadius(25)
                    Button(action: { level += 1
                        for _ in 0..<numberOfpeople {
                            listOfPeople.append(People())
                        }
                    },
                           label: { Text("Add")
                            .foregroundColor(Color.white)
                    })
                }
            }
        } else if level == 1 {
            VStack {
                HStack {
                    Text("Name of person")
                        .frame (width: 150, height: 20, alignment: .trailing)
                    TextField ("", text: $name)
                        .frame (width: 150, height: 20, alignment: .leading)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                }

                HStack {
                    Text("Number assigned")
                        .frame (width: 150, height: 20, alignment: .trailing)
                TextField( "", value: $assigned, format: .number)
                        .frame (width: 150, height: 20, alignment: .leading)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                }

                Button(action: {
                    listOfPeople[counter].name = name
                    listOfPeople[counter].numberAsigned = assigned
                    counter += 1
                    name = ""  // Let us clear the name
                }, label: {
                    Text ("Add Name")
                })
                .disabled(counter >= numberOfpeople)
            }
        }
    }
}
  • Thank you for the help! Next time I will upload the code as text. Sorry about that.

Add a Comment

Replies

Please, when you post code, post the code as text not images. And use code formatter tool.

struct ContentView: View {
    class People { // Uppercase name
        var name = ""
        var numberAsigned = 0
    }
    @State var level = 0
    @State var numberOfpeople = 0
    @State var name = ""
    @State var counter = 0
    @State var assigned = 0
    /*
     var person1 = people()
     var person2 = people()
     var person3 = people()
     var person4 = people()
     var person5 = people()
     var person6 = people()
     */
    
    var body: some View {
        var listOfPeople: [People] = []
        
        if level == 0 {
            VStack {
                TextField("How many people", value: $numberOfpeople, format: .number)
                    .frame (width: 100, height: 100)
                ZStack {
                    Rectangle()
                        .frame (width: 100, height: 100)
                        .cornerRadius(25)
                    Button(action: { level += 1 },
                           label: { Text("Add")
                            .foregroundColor(Color.white)
                    })
                }
            }
        } else if level == 1 {
            VStack {
                TextField ("Name of person", text: $name)
                TextField( "Number assigned", value: $assigned, format: .number)
                Button(action: {
                    listOfPeople[counter].name = name
                    listOfPeople[counter].numberAsigned = assigned
                    counter += 1
                }, label: {
                    Text ("Add Name")
                })
            }
        }
    }
}

Note also that class names should start with Uppercase (People)

You never append People to listOfPeople, which is declared as:

        var listOfPeople: [People] = []

Hence it is always empty and crashes when you try to access an element.

Then, listOfPeople should be a State var, otherwise it is reinitialized each time you redraw the view.

This works better:

struct ContentView: View {
    class People { // Uppercase name
        var name = ""
        var numberAsigned = 0  / probably a typo: numberAssigned
    }
    @State var level = 0
    @State var numberOfpeople = 0
    @State var name = ""
    @State var counter = 0
    @State var assigned = 0
    @State var listOfPeople: [People] = []
    
    var body: some View {
        
        if level == 0 {
            VStack {
                TextField("How many people", value: $numberOfpeople, format: .number)
                    .frame (width: 300, height: 100)
                ZStack {
                    Rectangle()
                        .frame (width: 100, height: 100)
                        .cornerRadius(25)
                    Button(action: { level += 1
                        for _ in 0..<numberOfpeople {
                            listOfPeople.append(People())
                        }
                    },
                           label: { Text("Add")
                            .foregroundColor(Color.white)
                    })
                }
            }
        } else if level == 1 {
            VStack {
                TextField ("Name of person", text: $name)
                TextField( "Number assigned", value: $assigned, format: .number)
                Button(action: {
                    listOfPeople[counter].name = name
                    listOfPeople[counter].numberAsigned = assigned
                    counter += 1
                }, label: {
                    Text ("Add Name")
                })
            }
        }
    }
}

Now you have to make your code more robust (disable button when completed), improve readability with labels for TextFields…

struct ContentView: View {
    class People { // Uppercase name
        var name = ""
        var numberAsigned = 0
    }
    @State var level = 0
    @State var numberOfpeople = 0
    @State var name = ""
    @State var counter = 0
    @State var assigned = 0
    @State var listOfPeople: [People] = []
    
    var body: some View {
        
        if level == 0 {
            VStack {
                HStack {
                    Text("How many people")
                        .frame (width: 150, height: 20, alignment: .trailing)
                    TextField("", value: $numberOfpeople, format: .number)
                        .frame (width: 50, height: 20, alignment: .leading)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                }
                ZStack {
                    Rectangle()
                        .frame(width: 100, height: 100)
                        .cornerRadius(25)
                    Button(action: { level += 1
                        for _ in 0..<numberOfpeople {
                            listOfPeople.append(People())
                        }
                    },
                           label: { Text("Add")
                            .foregroundColor(Color.white)
                    })
                }
            }
        } else if level == 1 {
            VStack {
                HStack {
                    Text("Name of person")
                        .frame (width: 150, height: 20, alignment: .trailing)
                    TextField ("", text: $name)
                        .frame (width: 150, height: 20, alignment: .leading)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                }

                HStack {
                    Text("Number assigned")
                        .frame (width: 150, height: 20, alignment: .trailing)
                TextField( "", value: $assigned, format: .number)
                        .frame (width: 150, height: 20, alignment: .leading)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                }

                Button(action: {
                    listOfPeople[counter].name = name
                    listOfPeople[counter].numberAsigned = assigned
                    counter += 1
                    name = ""  // Let us clear the name
                }, label: {
                    Text ("Add Name")
                })
                .disabled(counter >= numberOfpeople)
            }
        }
    }
}
  • Thank you for the help! Next time I will upload the code as text. Sorry about that.

Add a Comment