In der vorherigen Lektion haben wir die Möglichkeit hinzugefügt, Aufgaben zu erstellen. Diese Ergänzung hat die Anwendung zwar etwas nützlicher gemacht, es wäre jedoch auch sinnvoll, Elemente als erledigt zu markieren und Elemente zu löschen. Darauf konzentrieren wir uns in dieser Lektion.
Wenn Sie mit mir folgen möchten, stellen Sie sicher, dass Xcode 8.3.2 oder höher auf Ihrem Computer installiert ist. Sie können Xcode 8.3.2 im App Store von Apple herunterladen.
Um Elemente zu löschen, müssen wir zwei zusätzliche Methoden des implementieren UITableViewDataSource
Protokoll. Zunächst müssen wir der Tabellensicht mitteilen, welche Zeilen bearbeitet werden können, indem Sie das implementieren tableView (_: canEditRowAt :)
Methode. Wie Sie im folgenden Code-Snippet sehen können, ist die Implementierung unkompliziert. Wir sagen der Tabellensicht, dass jede Zeile durch Rückgabe bearbeitet werden kann wahr
.
func tableView (_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool return true
Die zweite Methode, die uns interessiert, ist tableView (_: commit: forRowAt :)
. Die Implementierung ist etwas komplexer, aber leicht verständlich.
func tableView (_ tableView: UITableView, Bearbeitungsschnitt übernehmen: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) if processingStyle == .delete // Aktualisierungselemente items.remove (at: indexPath.row) // Tabellenansicht tableView.deleteRows (at : [indexPath], mit: .right)
Wir beginnen mit der Überprüfung des Wertes von Bearbeitungsstil
, eine Aufzählung des Typs UITableViewCellEditingStyle
. Wir löschen einen Artikel nur, wenn der Wert von Bearbeitungsstil
entspricht UITableViewCellEditingStyle.delete
.
Swift ist jedoch schlauer. Weil es das weiß Bearbeitungsstil
ist vom Typ UITableViewCellEditingStyle
, wir können weglassen UITableViewCellEditingStyle
, den Namen der Aufzählung und schreiben .löschen
, Der Member-Wert der Aufzählung, an dem wir interessiert sind. Wenn Sie mit den Aufzählungen in Swift noch nicht vertraut sind, empfehle ich Ihnen, diesen kurzen Tipp zu den Aufzählungen in Swift zu lesen.
Als Nächstes aktualisieren wir die Datenquelle der Tabellensicht, Artikel
, durch Anrufen entfernen (bei :)
auf der Artikel
Eigenschaft, den korrekten Index übergeben. Wir aktualisieren auch die Tabellensicht durch Aufrufen deleteRows (bei: mit :)
auf Tabellenansicht
, in einem Array mit übergeben indexPath
und .Recht
um den Animationstyp anzugeben. Wie wir zuvor gesehen haben, können wir den Namen der Aufzählung weglassen, UITableViewRowAnimation
, da weiß Swift die Art des zweiten Arguments UITableViewRowAnimation
.
Der Benutzer sollte jetzt Elemente aus der Liste löschen können. Erstellen und starten Sie die Anwendung, um dies zu testen.
Um ein Element als erledigt zu markieren, fügen Sie der entsprechenden Zeile ein Häkchen hinzu. Dies impliziert, dass wir die Elemente verfolgen müssen, die der Benutzer als erledigt markiert hat. Zu diesem Zweck erklären wir eine neue Eigenschaft, die diese für uns verwaltet. Deklarieren Sie eine variable Eigenschaft, checkedItems
, vom Typ [Zeichenfolge]
, und initialisieren Sie es mit einem leeren Array.
var checkedItems: [String] = []
Im tableView (_: cellForRowAt :)
, wir prüfen ob checkedItems
enthält den jeweiligen Artikel durch Aufrufen der enthält (_ :)
Übergeben Sie das Element, das der aktuellen Zeile entspricht. Die Methode kehrt zurück wahr
ob checkedItems
enthält Artikel
.
func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell // Element abrufen lassen item = items [indexPath.row] // Dequeue Cell let cell = tableView.dequeueReusableCell (withIdentifier: "TableViewCell", für: indexPath) ) // Zelle konfigurieren cell.textLabel? .Text = item wenn checkedItems.contains (item) cell.accessoryType = .checkmark else cell.accessoryType = .none zurückgegebene Zelle
Ob Artikel
ist in gefunden checkedItems
, Wir setzen die Zelle zubehörart
Eigentum an .Häkchen
, ein Memberwert der UITableViewCellAccessoryType
Aufzählung. Ob Artikel
nicht gefunden, wir greifen zurück .keiner
als Zubehörtyp der Zelle.
Der nächste Schritt ist das Hinzufügen der Fähigkeit, ein Element als erledigt zu markieren, indem eine Methode des implementiert wird UITableViewDelegate
Protokoll, tableView (_: didSelectRowAt :)
. In dieser Delegatmethode rufen wir zuerst auf deselectRow (bei: animiert :)
auf Tabellenansicht
um die Zeile abzuwählen, die der Benutzer angetippt hat.
// MARK: - Table View Delegate Methods func tableView (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) tableView.deselectRow (at: indexPath, animated: true) // Element abrufen lassen item = items [indexPath.row] // Zelle abrufen let cell = tableView.cellForRow (at: indexPath) // Index des Elements suchen let index = checkedItems.index (of: item) wenn let index = index checkedItems.remove (at: index) cell? .AccessoryType =. none else checkedItems.append (item) cell? .accessoryType = .checkmark
Wir holen dann den entsprechenden Artikel ab Artikel
und eine Referenz auf die Zelle, die der angezapften Zeile entspricht. Wir fragen checkedItems
für den Index des entsprechenden Elements durch Aufrufen Index von:)
. Diese Methode gibt eine Option zurück Int
. Ob checkedItems
enthält Artikel
, wir entfernen es aus checkedItems
und setzen Sie den Zubehörtyp der Zelle auf .keiner
. Ob checkedItems
enthält nicht Artikel
, wir fügen es hinzu checkedItems
und setzen Sie den Zubehörtyp der Zelle auf .Häkchen
.
Mit diesen Ergänzungen kann der Benutzer Elemente jetzt als erledigt markieren. Erstellen Sie die Anwendung, und führen Sie sie aus, um sicherzustellen, dass alles wie erwartet funktioniert.
Die Anwendung speichert derzeit keinen Status zwischen den Starts. Um dies zu lösen, speichern wir die Artikel
und checkedItems
Arrays in der Benutzer-Standarddatenbank der Anwendung.
Erstellen Sie zunächst zwei Hilfsmethoden, loadItems ()
und loadCheckedItems ()
. Beachten Sie das Privatgelände
Schlüsselwort, das jeder Hilfsmethode vorangestellt wird. Das Privatgelände
Das Schlüsselwort teilt Swift mit, dass diese Methoden nur aus dem ViewController
Klasse.
// MARK: Private Helper Methods private func loadItems () let userDefaults = UserDefaults.standard wenn let items = userDefaults.object (forKey: "items") als? [String] self.items = items private func loadCheckedItems () let userDefaults = UserDefaults.standard wenn letItItems = userDefaults.object (forKey: "checkedItems") als lassen? [String] self.checkedItems = checkedItems
Das Privatgelände
Stichwort ist Teil von Swift Zugangskontrolle. Wie der Name schon sagt, definiert die Zugriffskontrolle, welcher Code auf welchen Code Zugriff hat. Die Zugriffsebenen gelten für Methoden, Funktionen, Typen usw., auf die sich Apple einfach bezieht Entitäten. Es gibt fünf Zugriffsebenen: offen, öffentlich, intern, Datei-privat und privat.
ViewController
Klasse sind nur für die ViewController
Klasse.ViewController
Klasse in ViewController.swift, Alle Entitäten, die als Datei-privat gekennzeichnet sind, sind in der Erweiterung nicht verfügbar, jedoch auf private Entitäten.Die Implementierung der Hilfsmethoden ist einfach, wenn Sie mit der UserDefaults
Klasse. Zur Vereinfachung der Verwendung speichern wir einen Verweis auf das Standardobjekt für Benutzervorgaben in einer Konstanten namens userDefaults
. Im Falle von loadItems ()
, wir fragen userDefaults
für das Objekt, das dem Schlüssel zugeordnet ist "Artikel"
und es an ein optionales Array von Strings weiterleiten. Wir packen das Optionale sicher aus, was bedeutet, dass wir den Wert in der Konstanten speichern Artikel
wenn das optional nicht ist Null
, und weisen Sie den Wert dem zu Artikel
Eigenschaft des View-Controllers.
Wenn die ob
Anweisung sieht verwirrend aus, dann werfen Sie einen Blick auf eine einfachere Version von loadItems ()
Methode im folgenden Beispiel. Das Ergebnis ist identisch. Der einzige Unterschied ist die Prägnanz.
private func loadItems () let userDefaults = UserDefaults.standard letoredItems = userDefaults.object (forKey: "items") als? [String] if let items = gespeicherte Artikel self.items = items
Die Implementierung von loadCheckedItems ()
ist identisch mit Ausnahme des Schlüssels, der zum Laden des in der Datenbank der Benutzervorgaben gespeicherten Objekts verwendet wird. Lasst uns loadItems ()
und loadCheckedItems ()
zu verwenden durch Aktualisieren der viewDidLoad ()
Methode.
func viewDidLoad () überschreiben super.viewDidLoad () // Titel setzen title = "Aufgabe" // Elemente füllen = "[Milch kaufen" "," Lernprogramm beenden "," Minecraft spielen "] // Status laden loadItems () loadCheckedItems () // Klasse für Cell Reuse tableView.register registrieren (UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
Um den Status zu sichern, implementieren wir zwei weitere private Hilfsmethoden, saveItems ()
und saveCheckedItems ()
. Die Logik ähnelt der von loadItems ()
und loadCheckedItems ()
. Der Unterschied besteht darin, dass wir Daten in der Datenbank der Benutzervorgaben speichern. Stellen Sie sicher, dass die Schlüssel in der setObject (_: forKey :)
Anrufe entsprechen denen, die in verwendet werden loadItems ()
und loadCheckedItems ()
.
private func saveItems () let userDefaults = UserDefaults.standard // Benutzereinstellungen aktualisieren userDefaults.set (items, forKey: "items") userDefaults.synchronize () private func saveCheckedItems () userDefaults.standard // aktualisieren lassen User Defaults userDefaults.set (checkedItems, forKey: "checkedItems") userDefaults.synchronize ()
Das synchronisieren()
Anruf ist nicht unbedingt erforderlich. Das Betriebssystem stellt sicher, dass die Daten, die Sie in der Datenbank mit den Benutzerstandards speichern, auf die Festplatte geschrieben werden irgendwann. Durch Aufruf synchronisieren()
, Sie weisen das Betriebssystem jedoch ausdrücklich an, alle ausstehenden Änderungen auf die Festplatte zu schreiben. Dies ist während der Entwicklung hilfreich, da das Betriebssystem Ihre Änderungen nicht auf die Festplatte schreibt, wenn Sie die Anwendung beenden. Es kann dann so aussehen, als ob etwas nicht richtig funktioniert.
Wir müssen anrufen saveItems ()
und saveCheckedItems ()
an einer Reihe von Orten. Um zu beginnen, rufen Sie an saveItems ()
wenn ein neues Element zur Liste hinzugefügt wird. Wir machen dies in der Delegiertenmethode des AddItemViewControllerDelegate
Protokoll.
// MARK: Elementansicht hinzufügen Controller Delegate-Methoden func controller (_ controller: AddItemViewController, didAddItem: String) // Datenquelle aktualisieren items.append (didAddItem) // Save State saveItems () // Reload Table View tableView.reloadData ( ) // Ablehnen Element hinzufügen View Controller abweisen (animiert: true)
Wenn sich der Status eines Elements im ändert tableView (_: didSelectRowAt :)
, wir aktualisieren checkedItems
. Es ist eine gute Idee, sie auch anzurufen saveCheckedItems ()
an diesem Punkt.
// MARK: - Table View Delegate Methods func tableView (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) tableView.deselectRow (at: indexPath, animated: true) // Element abrufen lassen item = items [indexPath.row] // Zelle abrufen let cell = tableView.cellForRow (at: indexPath) // Index des Elements suchen let index = checkedItems.index (of: item) wenn let index = index checkedItems.remove (at: index) cell? .AccessoryType =. none else checkedItems.append (item) cell? .accessoryType = .checkmark // Status speichern saveCheckedItems ()
Wenn ein Element gelöscht wird, beide Artikel
und checkedItems
aktualisiert werden. Um diese Änderung zu speichern, rufen wir beide auf saveItems ()
und saveCheckedItems ()
.
func tableView (_ tableView: UITableView, Bearbeitungsschnitt übernehmen: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) if processingStyle == .delete // Element abrufen let item = items [indexPath.row] // Elemente aufrüsten (at: indexPath) .row) if let index = checkedItems.index (of: item) checkedItems.remove (at: index) // Aktualisieren der Tabellenansicht tableView.deleteRows (at: [indexPath], with: .right) // Save State saveItems () saveCheckedItems ()
Das ist es. Erstellen Sie die Anwendung, und führen Sie sie aus, um Ihre Arbeit zu testen. Spielen Sie mit der Anwendung und beenden Sie sie. Wenn Sie die Anwendung erneut starten, sollte der letzte bekannte Status geladen und sichtbar sein.
Die Benutzererfahrung der Anwendung ist im Moment etwas zu wünschen übrig. Wenn jedes Element gelöscht wird oder wenn die Anwendung zum ersten Mal gestartet wird, wird dem Benutzer eine leere Tabellenansicht angezeigt. Das ist nicht so toll. Wir können dieses Problem lösen, indem wir eine Nachricht anzeigen, wenn keine Artikel vorhanden sind. Dies gibt mir auch die Möglichkeit, Ihnen ein anderes Feature von Swift zu zeigen, Immobilienbeobachter.
Beginnen wir damit, der Benutzeroberfläche ein Etikett für die Anzeige der Nachricht hinzuzufügen. Deklarieren Sie eine Filiale mit dem Namen messageLabel
vom Typ UILabel
in dem ViewController
Klasse, offen Hauptplatine, und fügen Sie der Ansicht des View-Controllers ein Label hinzu.
@IBOutlet var messageLabel: UILabel!
Fügen Sie dem Etikett die erforderlichen Layoutbeschränkungen hinzu und verbinden Sie es mit dem View-Controller messageLabel
Steckdose in der Verbindungsinspektor. Stellen Sie den Text der Beschriftung auf Sie haben keine Aufgaben. und zentrieren Sie den Beschriftungstext in der Attribute-Inspektor.
Das Nachrichtenetikett sollte nur sichtbar sein, wenn Artikel
enthält keine Elemente. In diesem Fall sollten Sie auch die Tabellenansicht ausblenden. Wir könnten dieses Problem lösen, indem wir verschiedene Checks hinzufügen ViewController
Klasse, aber ein bequemer und eleganter Ansatz ist die Verwendung eines Immobilienbeobachters.
Wie der Name schon sagt, beobachten Immobilienbeobachter eine Eigenschaft. Ein Eigenschaftsbeobachter wird immer dann aufgerufen, wenn sich eine Eigenschaft ändert, selbst wenn der neue Wert dem alten Wert entspricht. Es gibt zwei Arten von Immobilienbeobachtern.
willSet
: wird aufgerufen, bevor sich der Wert geändert hatdidSet
: wird aufgerufen, nachdem sich der Wert geändert hatFür unsere Zwecke werden wir die implementieren didSet
Beobachter für die Artikel
Eigentum. Sehen Sie sich die Syntax im folgenden Code-Snippet an.
var items: [String] = [] didSet let hasItems = items.count> 0 tableView.isHidden =! hasItems messageLabel.isHidden = hasItems
Das Konstrukt sieht auf den ersten Blick etwas seltsam aus, also lassen Sie mich erklären, was passiert. Wenn der didSet
Der Eigenschaftsbeobachter wird nach dem aufgerufen Artikel
Eigenschaft hat sich geändert, wir prüfen, ob die Artikel
Eigenschaft enthält alle Elemente. Basierend auf dem Wert der hasItems
konstant aktualisieren wir die Benutzeroberfläche. So einfach ist das.
Das didSet
Observer wird ein konstanter Parameter übergeben, der den Wert des alten Werts der Eigenschaft enthält. Im obigen Beispiel wird es weggelassen, weil wir es in unserer Implementierung nicht benötigen. Das folgende Beispiel zeigt, wie es verwendet werden kann.
var items: [String] = [] didSet (oldValue) if oldValue! = items let hasItems = items.count> 0 tableView.isHidden =! hasItems messageLabel.isHidden = hasItems
Das oldValue
Der Parameter im Beispiel hat keinen expliziten Typ, da Swift den Typ von kennt Artikel
Eigentum. Im Beispiel aktualisieren wir die Benutzeroberfläche nur, wenn der alte Wert vom neuen Wert abweicht.
EIN willSet
Beobachter arbeitet auf ähnliche Weise. Der Hauptunterschied besteht darin, dass der Parameter an den übergeben wird willSet
Der Beobachter ist eine Konstante, die den neuen Wert der Immobilie hält. Beachten Sie bei der Verwendung von Eigenschaftsbeobachtern, dass sie nicht bei der Initialisierung der Instanz aufgerufen werden.
Erstellen Sie die Anwendung, und führen Sie sie aus, um sicherzustellen, dass alles korrekt angeschlossen ist. Obwohl die Anwendung nicht perfekt ist und einige weitere Funktionen verwenden könnte, haben Sie Ihre erste iOS-Anwendung mit Swift erstellt.
Im Verlauf der letzten drei Lektionen dieser Serie haben Sie eine funktionale iOS-Anwendung mit objektorientierten Funktionen von Swift erstellt. Wenn Sie Erfahrung mit dem Programmieren und Entwickeln von Anwendungen haben, müssen Sie bemerkt haben, dass das aktuelle Datenmodell einige Mängel aufweist, um es leicht auszudrücken.
Das Speichern von Elementen als Zeichenfolgen und das Erstellen eines separaten Arrays zum Speichern des Status eines Elements ist keine gute Idee, wenn Sie eine geeignete Anwendung erstellen. Ein besserer Ansatz wäre die Schaffung eines separaten Machen
Klasse zum Modellieren von Objekten und speichern Sie sie in der Sandbox der Anwendung. Das ist unser Ziel für die nächste Lektion dieser Serie.
In der Zwischenzeit können Sie einige unserer anderen Kurse und Tutorials zur Entwicklung von iOS in Swift Language ausprobieren!