In the second chapter of this series, somewhat more sophisticated data should be displayed and information about a person is well suited. A class with properties for first and last name will suffice as a data model for the beginning. In addition a date of birth and an id. The latter will be used to uniquely identify the list items. As shown in the last chapter, this is required in conjunction with a ForEach loop. The type UUID automatically generates a unique value during initialization and thus takes over the task.
import Foundation
public class Person {
let id = UUID()
var firstName : String = ""
var lastName : String = ""
var birthday : Date = Date()
}
The class is sufficient as a data model, but it would be a big effort to create many different persons in one app. All values would have to be stored in the program code. Better would be a class, which takes over this task and generates persons with random properties. A kind of RandomPersonGenerator. Unfortunately, it is not easy for a program to generate names that do not consist of a random arrangement of letters. The class therefore contains arrays of first names and last names, from which entries are chosen at random. This limits the possible names, but the arrays can be extended at any time with little effort. With the randomElement function, Swift automatically returns a random value from the arrays. A bit more complex is the generation of a random date of birth. A TimeInterval is formed from two dates and then a random value is determined from this range. The class itself is a singleton. This means that only one instance of this class exists in the entire program. This is easily implemented by declaring the init method of the class as private. Access is exclusively via shared, a static field of the RandomPersonGenerator class.
import Foundation
public class RandomPersonGenerator {
static let shared = RandomPersonGenerator()
private var firstNames = [String]()
private var lastNames = [String]()
private let minBirthYear = 1960
private let maxBirthYear = 2010
private init()
{
firstNames.append(contentsOf: ["Rose", "Billie", "Ben", "Ken", "Michael", "Thomas", "Mike", "Kenzie"])
firstNames.append(contentsOf: ["Jane", "John", "Russel", "George", "Kagney", "Arnold"])
firstNames.append(contentsOf: ["Bruce", "Steve", "Patty", "Bill", "Ted", "Peter", "David", "May", "Gwen"])
lastNames.append(contentsOf: ["Swift", "Piper", "Steele", "Rogers", "Stark", "Hawkins", "Lee", "Kirby"] )
lastNames.append(contentsOf: ["Cambell", "Hart", "Jordan", "Fielding", "Crispin","Ford", "Jones"])
lastNames.append(contentsOf: ["Anderson", "Reeves", "Sagan", "Morgan", "Parker", "Watson"])
}
private func getRandomDate() -> Date {
var minComponents = DateComponents()
minComponents.year = self.minBirthYear
minComponents.month = 1
minComponents.day = 1
let minDate = Calendar.current.date(from: minComponents)
var maxComponents = DateComponents()
maxComponents.year = self.maxBirthYear
maxComponents.month = 12
maxComponents.day = 31
let maxDate = Calendar.current.date(from: maxComponents)
let span = TimeInterval.random(in: minDate!.timeIntervalSinceNow...maxDate!.timeIntervalSinceNow)
return Date(timeIntervalSinceNow: span)
}
public func generate() -> Person {
let person = Person()
person.firstName = self.firstNames.randomElement()!
person.lastName = self.lastNames.randomElement()!
person.birthday = self.getRandomDate()
return person
}
}
What is missing now is a class that manages a collection of Person instances. It should be called PersonRepository. As a parameter, the init method receives the number of persons that are to be randomly generated. If this sample data is not needed, a 0 can be passed. The repository can also manage persons that were not created with random data. The class is marked as ObservableObject and the persons property is marked as @Published. This way, the view is automatically updated when another person is added to the repository, or a person is deleted. More about this in one of the following chapters.
import SwiftUI
public class PersonsRepository : ObservableObject {
@Published var persons = [Person]()
init(randomPersonsCount : Int) {
for _ in 0..<randomPersonsCount {
self.persons.append(RandomPersonGenerator.shared.generate())
}
}
}
The view to display the list of people is also simple. Once again, a ForEach loop is used. This way, all persons from the repository can be displayed with only a few lines of program code. In the view, the repository is marked as ObservedObject. It is "observed" by the view. However, this only works if the class is an ObservableObject.
import SwiftUI
struct ContentView: View {
@ObservedObject var repo = PersonsRepository(randomPersonsCount: 10)
var body: some View {
List {
ForEach(self.repo.persons, id: \.id) { person in
Text("\(person.firstName) \(person.lastName)").font(.headline)
}
}
}
}
Written 2021-07-05 Tags: SwiftUI, List