Array with name and date in it

Hi,

I am trying to make an app that check people in. So far so good, but I got stuck on the following problem: I want to have an array with the name of the person and a date that this person will check in., in 1 array.
So when I select a date it will show a list all that people that will check that day.

Here the example of the array:

import Foundation
import SwiftUI

class Data: ObservableObject {

var id = UUID()

@Published var person = [“Micheal Jordan”,
“Scottie Pippen”,
“Dennis Rodman”,
“Steve Kerr”

]
@Published var personChecked = String

@Published var date: [String] = [ “6 April 2023”,
“7 April 2023”,
“20 April 2023”,
“28 April 2023”
]

}

How can I combine them together. I know I can use a JSON file and it will be much easier but this app won’t be using internet. When the person is checked in, it will be moved to personChecked.

Hello

I just want to confirm my understanding, you want to create an array of people with their check-in dates, and once checked-in, move the person to the personChecked list. Is that correct?

Hi,

Yes, a list with people and the date that they need to check in and once they checked in they will be moved to personChecked list, the last part I already have it done with .append. The reason that I want the date and name in one array is because when I select one date I want have the list of people that will check in that day.

@Tito

Hey Claudio, just a small point that may be something to consider is that naming your class as Data is probably not a good idea since Data is a swift type and there is a chance that you are going to cause some confusion if you ever want to use the Data type later on.

If you create a struct for your Data Model and you do something like this:

struct Data: Identifiable {
    var id: UUID
    var data: Data
    var name: String
}

It will throw an error related to ambiguity.

If you leave your class as named Data then you declare a field in your DataModel with a type of Data it will cause confusion too.

1 Like

Here’s an example of how you can structure your code using a struct and a list of tuples:

import Foundation
import SwiftUI

struct Person {
    var name: String
    var checkInDate: String
}

class Data: ObservableObject {
    var id = UUID()
    
    @Published var people: [Person] = [
        Person(name: "Michael Jordan", checkInDate: "6 April 2023"),
        Person(name: "Scottie Pippen", checkInDate: "7 April 2023"),
        Person(name: "Dennis Rodman", checkInDate: "20 April 2023"),
        Person(name: "Steve Kerr", checkInDate: "28 April 2023")
    ]
    
    @Published var personChecked: [Person] = []
    
    func checkIn(person: Person) {
        if let index = people.firstIndex(where: { $0.name == person.name }) {
            people.remove(at: index)
            personChecked.append(person)
        }
    }
    
    func peopleCheckingIn(on date: String) -> [Person] {
        return people.filter { $0.checkInDate == date }
    }
}

In this example, we define a Person struct with name and checkInDate properties. We create an array of Person objects for people . We also provide a checkIn(person:) function to move a person from people to personChecked .

Additionally, we provide a peopleCheckingIn(on:) function to get a list of people checking in on a specific date. You can use this function to display the list of people checking in on the selected date.

Please consider this also @Tito, I agree with @Chris_Parker recommendation.

Chris,

Thanks for the point and I totally agree with you. I will make the change asap.

Joash,

Thanks for the help.

I will try it out later on. Just for my understanding the struct Person part would be the Model in the MVVM. I know the class Data part would be the ViewModel part. Correct me if I am wrong.

Correct, although I agree, definitely don’t call this Data, especially as you’ve emphasized it’s actually part of the view model. Because “data” and “model” are pretty synonymous and calling it data when it’s really a view model is confusing

1 Like

I was testing the example but the “id = UUID()” has to be in the Struct Person right? I changed the Data into listOfPeople.
The code looks like this now:

struct Person {

var id = UUID()
var name: String
var checkInDate: String

}

class ListOfPeople: ObservableObject {

@Published var people: [Person] = [
        Person(name: "Michael Jordan", checkInDate: "6 April 2023"),
        Person(name: "Scottie Pippen", checkInDate: "7 April 2023"),
        Person(name: "Dennis Rodman", checkInDate: "20 April 2023"),
        Person(name: "Steve Kerr", checkInDate: "28 April 2023")
    ]

@Published var personChecked: [Person] = []
    
    func checkIn(person: Person) {
        if let index = people.firstIndex(where: { $0.name == person.name }) {
            people.remove(at: index)
            personChecked.append(person)
        }
    }
    
    func peopleCheckingIn(on date: String) -> [Person] {
        return people.filter { $0.checkInDate == date }
    }

You’re correct. If you want each Person to have a unique id, you should move the id property to the Person struct. Your updated code looks correct:

import Foundation
import SwiftUI

struct Person {
    var id = UUID()
    var name: String
    var checkInDate: String
}

class ListOfPeople: ObservableObject {
    @Published var people: [Person] = [
        Person(name: "Michael Jordan", checkInDate: "6 April 2023"),
        Person(name: "Scottie Pippen", checkInDate: "7 April 2023"),
        Person(name: "Dennis Rodman", checkInDate: "20 April 2023"),
        Person(name: "Steve Kerr", checkInDate: "28 April 2023")
    ]

    @Published var personChecked: [Person] = []
    
    func checkIn(person: Person) {
        if let index = people.firstIndex(where: { $0.id == person.id }) {
            people.remove(at: index)
            personChecked.append(person)
        }
    }
    
    func peopleCheckingIn(on date: String) -> [Person] {
        return people.filter { $0.checkInDate == date }
    }
}

With this code, each Person now has a unique id. Also, I updated the checkIn(person:) function to compare the id property instead of name, as it’s safer to use unique identifiers for such comparisons.

Thnx for the update.

I have a View called ShowList and I am using it only to show the name of people who are on the list. Now that the code is changed I m trying to access it like the following:

import SwiftUI

struct ShowList: View {

@EnvironmentObject var listOfPeople: ListOfPeople
@EnvironmentObject var enterName: EnterName

var body: some View {
    List {
        ForEach (listOfPeople.people.name, id: \.self) { person in
            Text(person)
                .padding(4)
            
        }
        .onDelete { indexSet in
            listOfPeople.person.remove(atOffsets: indexSet)
        
            
        }
    }
    .cornerRadius(20)
}

struct ShowList_Previews: PreviewProvider {
    static var previews: some View {
        ShowList()
            .environmentObject(ListOfPeople())
            .environmentObject(EnterName())
    }
}

}

After the code changed I had to change it also in the ForEach and to my opinion I should be:

ForEach (listOfPeople.people.name, id: .self) { person in
Text(person)
.padding(4)
but it gives me an error : Value of type ‘[Person]’ has no member ‘name’. I cant access listOfPeople.people.name from other view. What could be wrong?

What does your ObservableObject look like ie: ListOfPeople?

Here is a copy of it:

import Foundation
import SwiftUI

struct Person {

var id = UUID()
var name: String
var checkInDate: String

}

class ListOfPeople: ObservableObject {

@Published var people: [Person] = [
        Person(name: "Michael Jordan", checkInDate: "6 April 2023"),
        Person(name: "Scottie Pippen", checkInDate: "7 April 2023"),
        Person(name: "Dennis Rodman", checkInDate: "28 April 2023"),
        Person(name: "Steve Kerr", checkInDate: "28 April 2023"),
        Person(name: "Steph Curry", checkInDate: "6 April 2023"),
        Person(name: "Draymond Green", checkInDate: "7 April 2023")
    
    ]

@Published var personChecked: [Person] = []
    
func checkIn(person: Person) {
    if let index = people.firstIndex(where: { $0.id == person.id }) {
        people.remove(at: index)
        personChecked.append(person)
    }
}
    
    func peopleCheckingIn(on date: String) -> [Person] {
        return people.filter { $0.checkInDate == date }
    }

}

OK the first thing to note is that your ForEach should be just iterating over listOfPeople.people

ForEach (listOfPeople.people, id: \.self) { person in

and then the parameter in the closure person refers to an element of the array people and then in your Text you can say person.name. ie:

Text(person.name)

Your onDelete code should then read:

listOfPeople.people.remove(atOffsets: indexSet)

Thnx for the help and sharing your knowledge. I know now why it didn’t work. Now I got stocked on the following problem:

In the array people there are a couple of checkInDate with the same date, no problem with that. The problem comes when I try to use a Picker to select the date so I would get a list of the people who needs to check in that day. It gives me the all the double dates. Here is the code of the picker:

import SwiftUI

class ChangeViews: ObservableObject {
@Published var showAdd = false
@Published var dateSelection = “”
}

struct SettingsConfig: View {

@EnvironmentObject var changeViews: ChangeViews
@EnvironmentObject var listOfPeople: ListOfPeople


var body: some View {
    
    NavigationView {
        VStack {
            Toggle("Add Guest/ Delete Guest", isOn: $changeViews.showAdd)
                .font(.title2)
            
            Picker("Select Guest List date", selection: $changeViews.dateSelection) {
                ForEach(listOfPeople.people, id: \.checkInDate) { person in
                    Text(person.checkInDate)
                        .tag(0)
                    
                }
            
                
            }
            .pickerStyle(SegmentedPickerStyle())
            .font(.title2)
            .padding()

The idea is when I select a date in this view it will show the list of people for that day in an other view. The last part I already figure it out, but the problem is in that the picker shows double dates. I think it shows double dates because each checkInDates has it’s own unique id (correct me if I am wrong). How can I solve the problem.
Beside that I am planning to use the checkInDate to delete the whole list of people who has to be checkIn that day.

One of the problems I see is that the method you are using to store dates is a String starting with a number, a space, a Month and a space, then a year. This makes it near on impossible to sort your data by date if you needed to and it also means that the method you use to select a date is more difficult. If you want to stick with a date as a String then store it in the format of YYYY.MM.DD like this for example:
Person(name: "Michael Jordan", checkInDate: "2023.04.06")

This makes it easy to sort by date if you need to since even though it is a String, the format is such that 2023.04.06 is less than 2023.04.07 for example.

The better solution is to store the checkInDate as type Date. When you add a record, you pick a date using a Date Picker and when you want to select Dates that match a specific Date then once again you use a Date Picker to choose the date you want to search for and the test to find a checkInDate that matches that Date selected is much simpler.

Does that make sense?

Yes, it does and I changed it to Date.

struct Person: Hashable {

var id = UUID()
var name: String
var checkInDate = Date().formatted(.dateTime
    .day().month(.wide).year()
    .hour().minute())

}

class ListOfPeople: ObservableObject {

@Published var people: [Person] = [
    Person(name: "Michael Jordan", checkInDate: "6 April 2023"),
    Person(name: "Scottie Pippen", checkInDate: "7 April 2023"),
    Person(name: "Dennis Rodman", checkInDate: "28 April 2023"),
    Person(name: "Steve Kerr", checkInDate: "28 April 2023"),
    Person(name: "Steph Curry", checkInDate: "6 April 2023"),
    Person(name: "Draymond Green", checkInDate: "07 April 2023")
    
]

I made it to the point to create a DatePicker to add a Name and checkInDate to a person, but to select from a list of checkInDate through a DatePicker that I wasn’t able to made. How should it look like?

@Tito

Does your App really need to have the checkInDate defined as detailed as to include the Hour and Minute?

No, it don’t. I removed it just after the post.

struct Person: Hashable {

var id = UUID()
var name: String
var checkInDate = Date().formatted(.dateTime
    .day().month(.wide).year()
    )

}