Advertisement
  1. Code
  2. CloudKit

Erstellen einer Einkaufslistenanwendung mit CloudKit: Beziehungen hinzufügen

by
Read Time:21 minsLanguages:
This post is part of a series called Building a Shopping List Application With CloudKit.
Building a Shopping List Application With CloudKit: Adding Records
Building a Shopping List Application With CloudKit: Sharing Shopping Items

German (Deutsch) translation by Nikol Angelowa (you can also view the original English article)

Im vorherigen Tutorial dieser Serie haben wir die Möglichkeit hinzugefügt, Einkaufslisten hinzuzufügen, zu aktualisieren und zu entfernen. Eine Einkaufsliste ohne Artikel ist jedoch nicht sehr nützlich. In diesem Tutorial fügen wir die Möglichkeit hinzu, Artikel zu einer Einkaufsliste hinzuzufügen, zu aktualisieren und zu entfernen. Das bedeutet, dass wir mit Referenzen und der CKReference-Klasse arbeiten.

Außerdem schauen wir uns das Datenmodell der Einkaufslistenanwendung genauer an. Wie einfach sind Änderungen am Datenmodell und wie reagiert die Anwendung auf Änderungen, die wir im CloudKit-Dashboard vornehmen?

Voraussetzungen

Denken Sie daran, dass ich Xcode 7 und Swift 2 verwenden werde. Wenn Sie eine ältere Version von Xcode verwenden, denken Sie daran, dass Sie eine andere Version der Programmiersprache Swift verwenden.

In diesem Tutorial machen wir dort weiter, wo wir im zweiten Tutorial dieser Serie aufgehört haben. Sie können das Projekt von GitHub herunterladen oder klonen.

1. Details zur Einkaufsliste

Derzeit kann der Benutzer den Namen einer Einkaufsliste ändern, indem er auf den Detailoffenlegungsindikator tippt, aber der Benutzer sollte auch in der Lage sein, den Inhalt einer Einkaufsliste zu sehen, indem er auf einen in der Listenansichtssteuerung tippt. Damit dies funktioniert, benötigen wir zunächst eine neue UIViewController-Unterklasse.

Schritt 1: ListViewController erstellen

Die ListViewController-Klasse zeigt den Inhalt einer Einkaufsliste in einer Tabellenansicht an. Die Schnittstelle der ListViewController-Klasse ähnelt der der ListsViewController-Klasse. Wir importieren die Frameworks CloudKit und SVProgressHUD und passen die Klasse an die Protokolle UITableViewDataSource und UITableViewDelegate an. Da wir eine Tabellenansicht verwenden, deklarieren wir eine Konstante, ItemCell, die als Bezeichner für die ItemCell-Verwendung dient.

Wir deklarieren drei Ausgänge, messageLabel vom Typ UILabel!, tableView vom Typ UITableView! und activityIndicatorView vom Typ UIActivityIndicatorView!. Der Listenansicht-Controller behält eine Referenz auf die Einkaufsliste, die er in der list-Eneigenschaft anzeigt, die vom Typ CKRecord! ist. Die Artikel in der Einkaufsliste werden in der items-Eigenschaft gespeichert, die vom Typ [CKRecord] ist. Schließlich verwenden wir eine Hilfsvariable, selection, um zu verfolgen, welchen Artikel in der Einkaufsliste der Benutzer ausgewählt hat. Dies wird später in diesem Tutorial deutlich.

Schritt 2: Benutzeroberfläche erstellen

Öffnen Sie Main.storyboard, fügen Sie einen Ansichtscontroller hinzu, und legen Sie seine Klasse im Identitätsinspektor auf ListViewController fest. Wählen Sie die Prototypzelle des Listenansichtscontrollers aus, drücken Sie die Strg-Taste und ziehen Sie aus der Prototypzelle zum Listenansichtscontroller. Wählen Sie Anzeigen aus dem erscheinenden Menü und setzen Sie den Bezeichner im Attribute-Inspektor auf Liste.

Fügen Sie der Ansicht des Ansichtscontrollers eine Tabellenansicht, eine Beschriftung und eine Aktivitätsanzeigeansicht hinzu. Vergessen Sie nicht, sowohl die Ausgänge des View-Controllers als auch die der Table-View zu verdrahten.

Wählen Sie die Tabellenansicht aus und setzen Sie Prototypzellen im Attributeinspektor auf 1. Wählen Sie die Prototypzelle aus, setzen Sie Style auf Right Detail, Identifier auf ItemCell und Accessory auf Disclosure Indicator. So sollte der Ansichtscontroller aussehen, wenn Sie fertig sind.

List View ControllerList View ControllerList View Controller

Schritt 3: View Controller konfigurieren

Bevor wir das CloudKit-Framework erneut besuchen, müssen wir den Ansichtscontroller auf die Daten vorbereiten, die er empfangen wird. Beginnen Sie mit der Aktualisierung der Implementierung von viewDidLoad. Wir setzen den Titel des View-Controllers auf den Namen der Einkaufsliste und rufen zwei Hilfsmethoden auf, setupView und fetchItems.

Die setupView-Methode ist identisch mit der, die wir in der ListsViewController-Klasse implementiert haben.

Wenn wir schon dabei sind, implementieren wir auch eine andere bekannte Hilfsmethode, updateView. In updateView aktualisieren wir die Benutzeroberfläche des View-Controllers basierend auf den in der items-Eigenschaft gespeicherten Elementen.

Ich werde fetchItems vorerst leer lassen. Wir werden diese Methode wiederholen, sobald wir mit dem Einrichten des Listenansicht-Controllers fertig sind.

Schritt 4: Tabellenansicht-Datenquellenmethoden

Wir sind fast bereit, die Anwendung für einen weiteren Testlauf zu verwenden. Zuvor müssen wir das UITableViewDataSource-Protokoll implementieren. Wenn Sie die vorherigen Teile dieser Serie gelesen haben, wird Ihnen die Implementierung bekannt vorkommen.

Schritt 5: Auswahl bearbeiten

Um alles zusammenzufügen, müssen wir die ListsViewController-Klasse erneut besuchen. Beginnen Sie mit der Implementierung der tableView(_:didSelectRowAtIndexPath:)-Methode des UITableViewDelegate-Protokolls.

Wir müssen auch prepareForSegue(segue:sender:) aktualisieren, um den vor wenigen Augenblicken erstellten Übergang zu verarbeiten. Das bedeutet, dass wir der switch-Anweisung einen neuen case hinzufügen müssen.

Um den Compiler zufriedenzustellen, müssen wir auch die SegueList-Konstante oben in ListsViewController.swift deklarieren.

Erstellen Sie die Anwendung und führen Sie sie aus, um zu sehen, ob alles richtig verkabelt ist. Da wir die Methode fetchItems noch nicht implementiert haben, werden keine Elemente angezeigt. Das ist etwas, das wir beheben müssen.

2. Artikel holen

Schritt 1: Datensatztyp erstellen

Bevor wir Elemente aus dem CloudKit-Back-End abrufen können, müssen wir im CloudKit-Dashboard einen neuen Datensatztyp erstellen. Navigieren Sie zum CloudKit-Dashboard, erstellen Sie einen neuen Datensatztyp und nennen Sie ihn Items. Jedes Element sollte einen Namen haben. Erstellen Sie also ein neues Feld, setzen Sie den Feldnamen auf name und den Feldtyp auf String.

Jeder Artikel sollte auch wissen, zu welcher Einkaufsliste er gehört. Das bedeutet, dass jeder Artikel einen Verweis auf seine Einkaufsliste benötigt. Erstellen Sie ein neues Feld, setzen Sie den Feldnamen auf list und den Feldtyp auf Referenz. Der Feldtyp Referenz wurde genau zu diesem Zweck entwickelt, um Beziehungen zu verwalten.

Item Record TypeItem Record TypeItem Record Type

Gehen Sie zurück zu Xcode, öffnen Sie ListsViewController.swift und deklarieren Sie oben eine neue Konstante für den Datensatztyp Items.

Schritt 2: Artikel abrufen

Öffnen Sie ListViewController.swift und navigieren Sie zur Methode fetchItems. Die Implementierung ähnelt der fetchLists-Methode der ListsViewController-Klasse. Es gibt jedoch einen wichtigen Unterschied.

Der Unterschied zwischen fetchItems und fetchLists ist das Prädikat, das wir an den CKQuery-Initialisierer übergeben. Wir sind nicht an jedem Element in der privaten Datenbank des Benutzers interessiert. Wir interessieren uns nur für die Artikel, die einer bestimmten Einkaufsliste zugeordnet sind. Dies spiegelt sich im Prädikat der CKQuery-Instanz wider.

Wir erstellen das Prädikat, indem wir eine CKReference-Instanz übergeben, die wir durch Aufrufen von init(recordID:action:) erstellen. Diese Methode akzeptiert zwei Argumente, eine CKRecordID-Instanz, die auf den Einkaufslistendatensatz verweist, und eine CKReferenceAction-Instanz, die bestimmt, was passiert, wenn die Einkaufsliste gelöscht wird.

Referenzaktionen sind den Löschregeln in Core Data sehr ähnlich. Wenn das referenzierte Objekt, in diesem Beispiel die Einkaufsliste, gelöscht wird, überprüft das CloudKit-Framework die Referenzaktion, um zu bestimmen, was mit den Datensätzen geschehen soll, die einen Verweis auf den gelöschten Datensatz enthalten. Die CKReferenceAction-Enum hat zwei Memberwerte:

  • None: Wenn die Referenz gelöscht wird, geschieht nichts mit den Datensätzen, die auf den gelöschten Datensatz verweisen.
  • DeleteSelf: Wenn die Referenz gelöscht wird, wird auch jeder Datensatz gelöscht, der auf den gelöschten Datensatz verweist.

Da kein Artikel ohne Einkaufsliste existieren sollte, setzen wir die Referenzaktion auf DeleteSelf.

Die Methode processResponseForQuery(records:error:) enthält nichts Neues. Wir verarbeiten die Antwort der Anfrage und aktualisieren die Benutzeroberfläche entsprechend.

Erstellen Sie die Anwendung und führen Sie sie aus. Sie werden noch keine Artikel sehen, aber die Benutzeroberfläche sollte anzeigen, dass die Einkaufsliste leer ist.

3. Elemente hinzufügen

Schritt 1: AddItemViewControler erstellen

Es ist an der Zeit, die Möglichkeit zu implementieren, Artikel zu einer Einkaufsliste hinzuzufügen. Beginnen Sie mit dem Erstellen einer neuen UIViewController-Unterklasse, AddItemViewController. Die Schnittstelle des View-Controllers ähnelt der der AddListViewController-Klasse.

Oben importieren wir die Frameworks CloudKit und SVProgressHUD. Wir deklarieren das AddItemViewControllerDelegate-Protokoll, das denselben Zweck erfüllt wie das AddListViewControllerDelegate-Protokoll. Das Protokoll definiert zwei Methoden, eine zum Hinzufügen von Elementen und eine zum Aktualisieren von Elementen.

Wir deklarieren zwei Outlets, ein Textfeld und ein Bar-Button-Element. Wir deklarieren auch eine Eigenschaft für den Delegaten und eine Hilfsvariable, newItem, die uns hilft festzustellen, ob wir ein neues Element erstellen oder ein vorhandenes Element aktualisieren. Schließlich deklarieren wir eine list-Eigenschafts, um auf die Einkaufsliste zu verweisen, zu der der Artikel hinzugefügt wird, und einen item-Eigenschafts für den Artikel, den wir erstellen oder aktualisieren.

Bevor wir die Benutzeroberfläche erstellen, implementieren wir zwei Aktionen, die wir im Storyboard benötigen, cancel(_:) und save(_:). Wir werden die Implementierung der Aktion save(_:) später in diesem Tutorial aktualisieren.

Schritt 2: Benutzeroberfläche erstellen

Öffnen Sie Main.storyboard, fügen Sie ein Balkenschaltflächenelement zur Navigationsleiste des Listenansichts-Controllers hinzu und setzen Sie Systemelement im Attributeinspektor auf Hinzufügen. Ziehen Sie einen Ansichtscontroller aus der Objektbibliothek und legen Sie seine Klasse auf AddItemViewController fest. Erstellen Sie einen Übergang vom gerade erstellten Balkenschaltflächenelement zum Ansichtscontroller zum Hinzufügen von Elementen. Wählen Sie Anzeigen aus dem sich öffnenden Menü und setzen Sie den Bezeichner des Abschnitts auf ItemDetail.

Fügen Sie der Navigationsleiste des Ansichts-Controllers zum Hinzufügen von Elementen zwei Balkenschaltflächenelemente hinzu, eine Schaltfläche zum Abbrechen auf der linken Seite und eine Schaltfläche zum Speichern auf der rechten Seite. Verbinden Sie jedes Element der Leiste mit der entsprechenden Aktion. Fügen Sie der Ansicht des Ansichtscontrollers ein Textfeld hinzu und vergessen Sie nicht, die Ausgänge des Ansichtscontrollers anzuschließen. So sollte der Controller zum Hinzufügen von Elementen aussehen, wenn Sie fertig sind.

Add Item View ControllerAdd Item View ControllerAdd Item View Controller

Schritt 3: View Controller konfigurieren

Die Implementierung des View-Controllers zum Hinzufügen von Elementen enthält nichts, was wir noch nicht behandelt haben. Es gibt jedoch eine Ausnahme, die wir gleich besprechen werden. Beginnen wir mit der Konfiguration des Ansichtscontrollers in viewDidLoad.

Wir rufen setupView, eine Hilfsmethode, auf und aktualisieren den Wert von newItem. Wenn die item-Eigenschaft gleich nil ist, ist newItem gleich true. Auf diese Weise können wir feststellen, ob wir einen Einkaufslisteneintrag erstellen oder aktualisieren.

Außerdem fügen wir den Ansichtscontroller als Beobachter für Benachrichtigungen vom Typ UITextFieldTextDidChangeNotification hinzu. Dies bedeutet, dass der View-Controller benachrichtigt wird, wenn sich der Inhalt des nameTextField ändert.

In viewDidAppear(animated:) zeigen wir die Tastatur an, indem wir becomeFirstResponder auf nameTextField aufrufen.

Die Methode setupView ruft zwei Hilfsmethoden auf, updateNameTextField und updateSaveButton. Die Implementierung dieser Hilfsmethoden ist einfach. In updateNameTextField füllen wir das Textfeld. In updateSaveButton aktivieren oder deaktivieren wir die Speichern-Schaltfläche basierend auf dem Inhalt des Textfelds.

Bevor wir uns die aktualisierte Implementierung der Methode save(_:) ansehen, müssen wir die Methode textFieldDidChange(_:) implementieren. Alles, was wir tun, ist updateSaveButton aufzurufen, um den Speichern-Button zu aktivieren oder zu deaktivieren.

Schritt 4: Elemente speichern

Die Methode save(_:) ist die interessanteste Methode der AddItemViewController-Klasse, da sie uns zeigt, wie man mit CloudKit-Referenzen arbeitet. Sehen Sie sich unten die Implementierung der Methode save(_:) an.

Die meisten seiner Implementierungen sollten bekannt vorkommen, da wir das Speichern von Datensätzen in der AddListViewController-Klasse behandelt haben. Was uns am meisten interessiert, ist, wie der Artikel einen Bezug zu seiner Einkaufsliste behält. Wir erstellen zuerst eine CKReference-Instanz, indem wir den angegebenen Initialisierer init(recordID:action:) aufrufen. Wir haben die Details zum Erstellen einer CKReference-Instanz vor einigen Minuten behandelt, als wir die Abfrage zum Abrufen von Einkaufslistenelementen erstellt haben.

Es ist einfach, dem Artikel diese Referenz mitzuteilen. Wir rufen setObjec(_:forKey:) für die item-Eigenschaft auf und übergeben die CKReference-Instanz als Wert und "list" als Schlüssel. Der Schlüssel entspricht dem Feldnamen, den wir im CloudKit Dashboard zugewiesen haben. Das Speichern des Elements in iCloud ist identisch mit dem, was wir zuvor behandelt haben. So einfach können Sie mit CloudKit-Referenzen arbeiten.

Die Implementierung von processResponse(record:error:) enthält nichts Neues. Wir prüfen, ob Fehler aufgetreten sind, und benachrichtigen den Delegierten, wenn keine Fehler ausgegeben wurden.

Schritt 5: Aktualisieren von ListViewController

Wir haben noch einiges zu tun in der ListViewController-Klasse. Beginnen Sie mit der Anpassung der ListViewController-Klasse an das AddItemViewControllerDelegate-Protokoll. Dies ist auch ein guter Zeitpunkt, um eine Konstante für den segue mit dem Bezeichner ItemDetail zu deklarieren.

Die Implementierung des AddItemViewControllerDelegate-Protokolls ist trivial. In controller(_:didAddItem:) fügen wir das neue Element zu items hinzu, sortieren items, laden die Tabellenansicht neu und rufen updateView auf.

Noch einfacher ist die Implementierung von controller(_:didUpdateItem:). Wir sortieren items und laden die Tabellenansicht neu.

In sortItems sortieren wir das Array der CKRecord-Instanzen nach Namen mithilfe der Funktion sortInPlace, einer Methode des MutableCollectionType-Protokolls.

Es gibt zwei weitere Funktionen, die wir implementieren müssen, nämlich das Aktualisieren und Löschen von Einkaufslistenelementen.

Schritt 6: Elemente löschen

Um Elemente zu löschen, müssen wir tableView(_:commitEditingStyle:forRowAtIndexPath:) des UITableViewDataSource-Protokolls implementieren. Wir holen das zu löschende Einkaufslistenelement und übergeben es an die Methode deleteRecord(_:).

Die Implementierung von deleteRecord(_:) enthält nichts Neues. Wir rufen deleteRecordWithID(_:completionHandler:) in der privaten Datenbank auf und verarbeiten die Antwort im Abschlusshandler.

In processResponseForDeleteRequest(record:recordID:error:) aktualisieren wir die items-Eigenschaft und die Benutzeroberfläche. Wenn etwas schief gelaufen ist, benachrichtigen wir den Benutzer, indem wir eine Warnung anzeigen.

Schritt 7: Elemente aktualisieren

Der Benutzer kann ein Element aktualisieren, indem er auf das Detailoffenlegungskennzeichen tippt. Dies bedeutet, dass wir die Delegatmethode tableView(_:accessoireButtonTappedForRowWithIndexPath:) implementieren müssen. Bei dieser Methode speichern wir die Auswahl des Benutzers und führen die ListDetail-Überleitung manuell durch. Beachten Sie, dass in der tableView(_:didSelectRowAtIndexPath:)-Methode nichts passiert. Wir deaktivieren lediglich die Zeile, die der Benutzer angetippt hat.

In prepareForSegue(_:sender:) rufen wir das Einkaufslistenelement mit dem Wert der selection-Eigenschaft ab und konfigurieren den Zielansichtscontroller, eine Instanz der AddItemViewController-Klasse.

Das ist alles, was wir tun müssen, um Artikel auf der Einkaufsliste zu löschen und zu aktualisieren. Im nächsten Abschnitt untersuchen wir, wie einfach es ist, das Datenmodell im CloudKit-Dashboard zu aktualisieren.

4. Aktualisieren des Datenmodells

Wenn Sie schon einmal mit Core Data gearbeitet haben, wissen Sie, dass die Aktualisierung des Datenmodells mit Vorsicht erfolgen sollte. Sie müssen sicherstellen, dass die persistenten Speicher der Anwendung nicht beschädigt oder beschädigt werden. CloudKit ist etwas flexibler.

Der Datensatztyp Items hat derzeit zwei Felder, name und list. Ich möchte Ihnen zeigen, was es bedeutet, das Datenmodell durch Hinzufügen eines neuen Felds zu aktualisieren. Öffnen Sie das CloudKit-Dashboard und fügen Sie dem Items-Datensatz ein neues Feld hinzu. Setzen Sie den Feldnamen auf number und den Feldtyp auf Int(64). Vergessen Sie nicht, Ihre Änderungen zu speichern.

Update Item Record TypeUpdate Item Record TypeUpdate Item Record Type

Fügen wir nun die Möglichkeit hinzu, die Nummer eines Artikels zu ändern. Öffnen Sie AddItemViewController.swift und deklarieren Sie zwei Ausgänge, ein Label und einen Stepper.

Wir müssen auch eine Aktion hinzufügen, die ausgelöst wird, wenn sich der Wert des Steppers ändert. In numberDidChange(_:) aktualisieren wir den Inhalt von numberLabel.

Öffnen Sie Main.storyboard und fügen Sie dem Controller zum Hinzufügen von Elementen ein Label und einen Stepper hinzu. Verbinden Sie die Ausgänge des View-Controllers mit den entsprechenden Benutzeroberflächenelementen und verbinden Sie die numberDidChange(_:)-Aktion mit dem Stepper für das Value Changed-Ereignis.

Update Add Item View ControllerUpdate Add Item View ControllerUpdate Add Item View Controller

Die Aktion save(_:) der AddItemViewController-Klasse ändert sich ebenfalls geringfügig. Mal sehen, wie das aussieht.

Wir müssen nur zwei Zeilen Code hinzufügen. Oben speichern wir den Wert des Steppers in einer konstanten number. Wenn wir item konfigurieren, legen wir item als Wert für den "number"-Schlüssel fest und das ist alles.

Wir müssen auch eine Hilfsmethode implementieren, um die Benutzeroberfläche des Controllers für die Ansicht zum Hinzufügen von Elementen zu aktualisieren. Die Methode updateNumberStepper überprüft, ob der Datensatz ein Feld namens number enthält, und aktualisiert den Stepper, falls dies der Fall ist.

Wir rufen updateNumberStepper in der setupView-Methode der AddItemViewController-Klasse auf.

Um die Nummer jedes Elements zu visualisieren, müssen wir eine Änderung am ListViewController vornehmen. In tableView(_:cellForRowAtIndexPath:) setzen wir den Inhalt der rechten Beschriftung der Zelle auf den Wert des Zahlenfelds des Elements.

Das ist alles, was wir tun müssen, um die Änderungen, die wir am Datenmodell vorgenommen haben, umzusetzen. Eine Migration oder ähnliches ist nicht erforderlich. CloudKit kümmert sich um die kleinen Details.

Abschluss

Sie sollten jetzt über eine ordnungsgemäße Grundlage des CloudKit-Frameworks verfügen. Ich hoffe, Sie stimmen zu, dass Apple mit dem Framework und dem CloudKit Dashboard großartige Arbeit geleistet hat. Es gibt vieles, was wir in dieser Serie noch nicht behandelt haben, aber das sollte Ihnen genug geben, um mit CloudKit in Ihren eigenen Projekten zu beginnen.

Wenn Sie Fragen oder Kommentare haben, können Sie diese gerne in den Kommentaren unten hinterlassen oder mich auf Twitter kontaktieren.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.