Im zweiten Kapitel diese Reihe sollen etwas anspruchsvollere Daten angezeigt werden und gut eignen sich die Informationen zu einer Person. Eine Klasse mit Eigenschaften für Vor- und Nachname wird als Datenmodel für den Anfang genügen. Dazu ein Geburtsdatum und eine Id. Letztere werden wird verwendet, um die Listenelemente eindeutig zu identifizieren. Wie im letzten Kapitel gezeigt ist das, in Verbindung mit einer ForEach-Schleife, erforderlich. Der Typ UUID erzeugt bei der Initialisierung automatisch einen einmaligen Wert und übernimmt somit die Aufgabe.
import Foundation
public class Person {
let id = UUID()
var firstName : String = ""
var lastName : String = ""
var birthday : Date = Date()
}
Als Datenmodel genügt die Klasse aber es wäre en großer Aufwand, in einer App viele unterschiedliche Personen zu erzeugen. Sämtliche Werte müssten im Programmcode hinterlegt werden. Besser wäre eine Klasse, welche diese Aufgabe übernimmt und Personen mit zufälligen Eigenschaften erzeugt. Ein Art RandomPersonGenerator. Leider ist es für ein Programm nicht leicht, Namen zu generieren, die nicht aus einer zufälligen Anordnung von Buchstaben bestehen. Die Klasse enthält daher Arrays von Vornamen und Nachnamen, aus der zufällig Einträge gewählt werden. Das schränkt die möglichen Namen zwar ein, die Arrays können aber jederzeit und mit geringem Aufwand erweitert werden. Mit der Funktion randomElement liefert Swift automatisch einen zufälligen Wert aus den Arrays. Etwas aufwändiger ist die Generierung eines zufälligen Geburtsdatums. Aus zwei Daten wird eine TimeInterval gebildet und anschließend ein zufälliger Wert aus diesem Bereich ermittelt. Die Klasse selbst ist ein Singleton. Das bedeutet, im gesamten Programm existiert nur eine einzige Instanz dieser Klasse. Das ist leicht umzusetzen, indem man die init-Methode der Klasse als private deklariert. Der Zugriff geschieht ausschließlich über shared, einem statischem Feld der Klasse RandomPersonGenerator.
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
}
}
Was jetzt noch fehlt, ist eine Klasse, welche eine Auflistung von Person-Instanzen verwaltet. Sie soll PersonRepository heißen. Als Parameter erhält die init-Methode die Anzahl von Personen, die zufällig erzeugt werden sollen. Werden diese Beispieldaten nicht benötigt, kann eine 0 übergeben werden. Das Repository kann auch Personen verwalten, die nicht mit zufälligen Daten erzeugt wurden. Die Klasse wird als ObservableObject gekennzeichnet und die Eigenschaft persons als @Published. So wird erreicht, dass sich die View automatisch aktualisiert, wenn dem Repository eine weitere Person hinzugefügt wird, oder eine Person gelöscht wird. Mehr dazu in einem der folgenden Kapitel.
import SwiftUI
public class PersonsRepository : ObservableObject {
@Published var persons = [Person]()
init(randomPersonsCount : Int) {
for _ in 0..<randomPersonsCount {
self.persons.append(RandomPersonGenerator.shared.generate())
}
}
}
Der View, um die Liste der Personen anzuzeigen, ist ebenfalls einfach aufgebaut. Erneut kommt eine ForEach-Schleife zum Einsatz. So können mit nur wenigen Zeilen Programmcode alle Personen aus dem Repository angezeigt werden. In der View wird das Repository als ObservedObject gekennzeichnet. Es wird von der View »beobachtet«. Das funktioniert jedoch nur, wenn die Klasse ein ObservableObject ist. Ein »beobachtbares Objekt«.
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)
}
}
}
}
Geschrieben am: 05.07.2021 Technologien: SwiftUI, List