Schnell von Grund auf Zugangskontrolle und Objektbeobachter

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.

Voraussetzungen

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.

1. Elemente löschen

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.

2. Objekte abhaken

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.

3. Zustand speichern

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.

Schritt 1: Ladezustand

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.

  • Open / Public: Als "offen" oder "öffentlich" markierte Entitäten sind für Entitäten zugänglich, die in demselben Modul definiert sind, sowie auf andere Module. Dies ist ideal, um die Schnittstelle eines Frameworks darzustellen. Es gibt mehrere Unterschiede zwischen der offenen und der öffentlichen Zugriffsebene. Weitere Informationen zu diesen Unterschieden finden Sie in der Programmiersprache Swift.
  • Intern: Dies ist die Standardzugriffsebene. Wenn also keine Zugriffsebene angegeben wird, gilt diese Zugriffsebene. Auf eine Entität mit einer Zugriffsebene von intern können nur Entitäten zugreifen, die im selben Modul definiert sind.
  • Datei-Privat: Auf eine als file-private deklarierte Entität können nur Entitäten zugreifen, die in derselben Quelldatei definiert sind. Zum Beispiel die privaten Hilfsmethoden, die in definiert sind ViewController Klasse sind nur für die ViewController Klasse.
  • Privatgelände: Privat ist File-Private sehr ähnlich. Der einzige Unterschied besteht darin, dass eine als privat deklarierte Entität nur von der Deklaration aus zugänglich ist, in der sie eingeschlossen ist. Zum Beispiel, wenn wir eine Erweiterung für die erstellen 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")

Schritt 2: Status speichern

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.

4. Immobilienbeobachter

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.

Schritt 1: Etikett hinzufügen

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.

Schritt 2: Implementieren eines Property Observer

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 hat
  • didSet: wird aufgerufen, nachdem sich der Wert geändert hat

Fü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.

Fazit

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!