Die Synchronisierung von Anwendungsdaten auf Geräten ist eine komplexe und schwierige Aufgabe. Zum Glück hat Apple genau deshalb iCloud gebaut. In dieser Tuts + Premium-Serie erfahren Sie, wie iCloud funktioniert und wie Ihre Anwendungen Daten nahtlos auf mehreren Geräten gemeinsam nutzen können.
In der zweiten Ausgabe dieser Serie habe ich Ihnen gezeigt, wie Sie den Key-Value-Speicher von iCloud nutzen können, um kleine Mengen von Benutzerdaten auf mehreren Geräten synchron zu halten. Obwohl die Speicherung von Schlüsselwerten einfach zu verwenden und anzuwenden ist, besteht eine der Nachteile darin, dass die zu speichernde Datenmenge begrenzt ist. Beachten Sie, dass jede Anwendung nur 1 MB Daten speichern kann und die Anzahl der Schlüssel-Wert-Paare auf 1024 begrenzt ist. Wie ich am Ende des vorherigen Lernprogramms erwähnt habe, könnte unser Lesezeichen-Manager auf diese Einschränkung stoßen, wenn einer unserer Benutzer speichern möchte viele Lesezeichen.
Die Lösung für dieses Problem besteht darin, zum Speichern von Lesezeichen von iCloud Key-Value Storage zu iCloud Document Storage zu wechseln. In Bezug auf den Festplattenspeicher ist der iCloud Document Storage nur durch den iCloud-Speicher des Benutzers begrenzt. ICloud Document Storage ist die ideale Lösung für unseren Lesezeichen-Manager, da ein kostenloses Konto mit 5 GB Datenspeicher ausgestattet ist. In diesem Lernprogramm werden wir den Lesezeichen-Manager von der Verwendung von iCloud Key-Value Storage zur Verwendung von iCloud Document Storage umgestalten.
Ich möchte betonen, dass es wichtig ist, dass Sie den ersten und den zweiten Teil dieser Serie gelesen haben, bevor Sie diesen Artikel lesen. In diesem Lernprogramm werden wir unseren Lesezeichen-Manager umgestalten, indem wir auf den Grundlagen von Teil 2 der Serie aufbauen.
UID-Dokument
Mit der Einführung von iCloud hat Apple auch gemacht UID-Dokument
für Entwickler verfügbar. Die Ingenieure bei Apple haben geschaffen UID-Dokument
mit iCloud im auge. UID-Dokument
vereinfacht die iCloud-Integration für dokumentenbasierte Anwendungen. Es ist jedoch wichtig, das zu beachten UID-Dokument
bietet weit mehr als nur eine einfach zu verwendende API für die iCloud-Integration.
Dokumentbasierte Anwendungen müssen sich einer Reihe von Herausforderungen stellen, z. B. (1) Lesen und Schreiben von Daten von und auf die Festplatte, ohne die Benutzeroberfläche zu blockieren, (2) Daten in geeigneten Intervallen auf der Festplatte zu speichern, und (3) optional Integration in iCloud. UID-Dokument
bietet integrierte Lösungen für diese Herausforderungen.
Bevor wir anfangen mit zu arbeiten UID-Dokument
, Ich möchte klar machen, was UID-Dokument
ist und was es nicht ist. UID-Dokument
ist ein Controller-Objekt, das genau wie ein oder mehrere Modelle verwaltet UIViewController
steuert und verwaltet eine oder mehrere Ansichten. UID-Dokument
speichert keine Daten, verwaltet jedoch die Modellobjekte, die die Daten des Benutzers enthalten. Dies ist ein wichtiges Verständnis, das klarer wird, wenn wir mit der Umgestaltung unserer Anwendung beginnen UID-Dokument
.
Ein weiteres wichtiges Konzept ist die Funktionsweise von Lese- und Schreibvorgängen bei der Verwendung UID-Dokument
. Wenn Sie sich entscheiden, zu verwenden UID-Dokument
In Ihrer Anwendung müssen Sie sich keine Gedanken darüber machen, dass der Haupt-Thread beim Lesen oder Schreiben von Daten auf die Festplatte blockiert wird. Beim Benutzen UID-Dokument
, Das Betriebssystem wird automatisch eine Reihe von Aufgaben für Sie in einer Hintergrundwarteschlange erledigen und sicherstellen, dass der Hauptthread reagiert. Ich möchte mir einen Moment Zeit nehmen und jede Operation detaillierter erklären, um Ihnen ein besseres Verständnis der verschiedenen beweglichen Teile zu vermitteln, die beteiligt sind.
Beginnen wir mit dem Lesen von Daten von der Festplatte. Die Leseoperation beginnt mit einer offenen Operation, die in der anrufenden Warteschlange initiiert wird. Der Öffnungsvorgang wird gestartet, wenn ein Dokument durch Senden einer Nachricht von geöffnet wird openWithCompletionHandler:. Wir übergeben einen Beendigungshandler, der aufgerufen wird, wenn der gesamte Lesevorgang abgeschlossen ist. Dies ist ein wichtiger Aspekt der Lese- und Schreibvorgänge. Das Lesen oder Schreiben der Daten von oder auf die Festplatte kann eine nicht unbedeutende Zeit in Anspruch nehmen. Wir möchten dies nicht im Haupt-Thread tun und die Benutzeroberfläche blockieren. Der eigentliche Lesevorgang findet in einer vom Betriebssystem verwalteten Hintergrundwarteschlange statt. Wenn der Lesevorgang abgeschlossen ist, wird die loadFromContents: ofType: Fehler: Methode wird im Dokument aufgerufen. Diese Methode sendet UID-Dokument
die Daten, die zum Initialisieren der verwalteten Modelle erforderlich sind. Der Beendigungs-Handler wird aufgerufen, wenn dieser Prozess abgeschlossen ist. Dies bedeutet, dass wir auf das Laden des Dokuments reagieren können, indem wir beispielsweise die Benutzeroberfläche mit dem Inhalt des Dokuments aktualisieren.
Der Schreibvorgang ist ähnlich. Es beginnt mit einem Speichervorgang, der in der anrufenden Warteschlange durch Senden ausgelöst wird saveToURL: forSaveOperation: completionHandler: zum Dokumentobjekt. Wie beim Lesevorgang übergeben wir einen Beendigungshandler, der aufgerufen wird, wenn der Schreibvorgang abgeschlossen ist. Das Schreiben von Daten auf die Festplatte erfolgt in einer Hintergrundwarteschlange. Das Betriebssystem fragt UID-Dokument
für eine Momentaufnahme seiner Modelldaten durch Senden einer Nachricht von contentsForType: Fehler:. Der Beendigungs-Handler wird aufgerufen, wenn der Schreibvorgang abgeschlossen ist. Dies gibt uns die Möglichkeit, die Benutzeroberfläche zu aktualisieren.
UID-Dokument
ist eine Basisklasse und soll nicht direkt verwendet werden. Wir müssen eine Unterklasse bilden UID-Dokument
und passen sie an unsere Bedürfnisse an. Mit anderen Worten, wir unterteilen die Klasse UID-Dokument
damit es über unser Modell Bescheid weiß und wie es zu handhaben ist. In seiner grundlegendsten Form, Unterklasse UID-Dokument
nur erfordert, dass wir überschreiben loadFromContents: ofType: Fehler: zum Lesen und contentsForType: Fehler: zum Schreiben.
Verwirrt? Du solltest sein. Obwohl UID-Dokument
macht das Leben viel einfacher, es ist eine fortgeschrittene Klasse und es handelt sich um ein komplexes Thema. Ich bin jedoch überzeugt, dass Sie mit dokumentenbasierten Anwendungen gut vertraut werden, sobald wir unsere Anwendung überarbeitet haben.
Bevor wir fortfahren, möchte ich klarstellen, was unsere Ziele für dieses Tutorial sind. Das Hauptziel besteht darin, unsere Anwendung zu refactorisieren, um iCloud Document Storage anstelle von iCloud Key Value Storage zu verwenden. Dies bedeutet, dass wir Gebrauch machen werden UID-Dokument
und Unterklasse, um unsere Bedürfnisse zu erfüllen. Außerdem erstellen wir eine benutzerdefinierte Modellklasse für unser Lesezeichen, die von verwendet und verwaltet wird UID-Dokument
Unterklasse.
Derzeit ist unsere Anwendung so konfiguriert, dass nur der Schlüsselwertspeicher verwendet wird. Um die Dokumentenspeicherung zu aktivieren, müssen wir zunächst die Berechtigungen unserer Anwendung konfigurieren. Öffne das Ziel-Editor indem Sie unsere Anwendung in der Projektnavigator und wählen Sie das einzige Ziel aus der Zielliste aus. In dem Ansprüche Abschnitt sollten Sie sehen iCloud-Container unten iCloud-Schlüsselwertspeicher. Die Liste neben iCloud-Container ist momentan leer. Klicken Sie unten in der Liste auf die Plus-Schaltfläche. Sie sehen, dass Xcode eine iCloud-Container-ID für Sie erstellt, die der Bundle-ID Ihrer Anwendung entspricht.
Was ist ein iCloud-Container? Wie der Name schon sagt, handelt es sich um einen Container im iCloud-Datenspeicher des Benutzers. Durch Angabe eines (oder mehrerer) iCloud-Containers in der Berechtigungsdatei unserer Anwendung teilen wir dem Betriebssystem mit, auf welche Container unsere Anwendung Zugriff hat.
Im vorherigen Tutorial haben wir jedes Lesezeichen als Instanz von gespeichert NSDictionary
, Dies ist jedoch keine gute Lösung für eine dokumentenbasierte Anwendung. Stattdessen erstellen wir eine benutzerdefinierte Lesezeichenklasse, mit der wir ihre Daten einfach archivieren können.
Erstelle eine neue NSObject
Unterklasse durch Auswahl Datei Wählen Sie im Menü Neu, und dann Datei… . Wählen Kakao-Touch aus dem linken Feld und wählen Sie Ziel-C-Klasse aus der Liste der Vorlagen auf der rechten Seite. Geben Sie der Klasse einen Namen Lesezeichen und stellen Sie sicher, dass es eine Unterklasse von ist NSObject. Geben Sie an, wo Sie die neue Klasse speichern möchten, und klicken Sie auf Erstellen.
In der Header-Datei unseres Modells fügen wir die beiden Eigenschaften des Lesezeichenmodells hinzu, das wir im vorherigen Tutorial verwendet haben: a Name und ein URL. Beide Eigenschaften sind Instanzen von NSString
. Wir deklarieren auch einen bestimmten Initialisierer, der einen Namen und eine URL als Parameter verwendet. Schließlich ist es wichtig sicherzustellen, dass unsere Lesezeichen
Klasse entspricht der NSCoding
Protokoll.
#einführen@Interface-Lesezeichen: NSObject NSString * _name; NSString * _url; @ property (nonatomic, copy) NSString * name; @ property (nonatomic, copy) NSString * url; - (id) initWithName: (NSString *) Name und URL: (NSString *) URL; @Ende
In der Implementierungsdatei unseres Modells definieren wir zunächst zwei Konstanten für den Namen und die URL unseres Lesezeichens. Dies ist eine gute Praxis, da dadurch die Wahrscheinlichkeit minimiert wird, dass wir die Schlüssel, die wir in Kürze verwenden werden, falsch eingeben. Als Nächstes implementieren wir unsere Initialisierungsmethode. Diese Methode ist unkompliziert. Wir initialisieren unsere Instanz und weisen den Variablen der Lesezeicheninstanz den Namen und die URL zu.
Der wichtige Teil ist die Implementierung der erforderlichen Methoden zur Erstellung der Lesezeichen
Klasse entsprechen der NSCoding
Protokoll. Wenn die NSCoding
Protokoll ist neu für Sie, dann empfehle ich Ihnen, das Programmierungshandbuch für Archive und Serialisierungen zu lesen, da dies ein wichtiges Thema für jeden Cocoa-Touch-Entwickler ist. Der Kern davon ist, dass die NSCoding
Mit diesem Protokoll können wir Instanzen der Lesezeichen
Klasse.
#import "Bookmark.h" #define kBookmarkName @ "Bookmarkname" #define kBookmarkURL @ "Lesezeichen-URL" @implementation Bookmark @synthesize name = _name, url = _url; #pragma mark - #pragma mark Initialisierung - (id) initWithName: (NSString *) name undURL: (NSString *) url self = [super init]; if (self) self.name = name; self.url = url; return self; #pragma mark - #pragma mark NSCoding Protocol - (void) encodeWithCoder: (NSCoder *) -Kodierer [coder encodeObject: self.name forKey: kBookmarkName]; [coder encodeObject: self.url forKey: kBookmarkURLL]; - (id) initWithCoder: (NSCoder *) - Codierer self = [super init]; if (self! = nil) self.name = [coder decodeObjectForKey: kBookmarkName]; self.url = [coder decodeObjectForKey: kBookmarkURLL]; return self; @Ende
Unterklasse UID-Dokument
ist nicht so schwierig, wie Sie vielleicht denken. Wie bereits erwähnt, müssen wir nur zwei Methoden überschreiben und eine Eigenschaft für das Lesezeichenmodell erstellen, das verwaltet werden soll.
Erstellen Sie eine neue Klasse wie wir es für unsere gemacht haben Lesezeichen
Klasse und geben Sie einen Namen von BookmarkDocument
. Stellen Sie sicher, dass es sich um eine Unterklasse von handelt UID-Dokument
. In der Header-Datei unseres UID-Dokument
Unterklasse fügen wir eine Vorwärtsdeklaration für die hinzu Lesezeichen
Klasse und wir erstellen eine Eigenschaft für unser Lesezeichenmodell. Vergessen Sie nicht, Accessoren für diese Eigenschaft zu synthetisieren.
#einführen@class Lesezeichen; @Interface BookmarkDocument: UIDocument Bookmark * _bookmark; @ property (nichtatomisch, stark) Lesezeichen * Lesezeichen; @Ende
In der Implementierungsdatei importieren wir die Header-Datei von Lesezeichen klassifizieren und definieren Sie eine weitere Konstante, die als Schlüssel für das Archivieren und Aufheben der Archivierung des Lesezeichenmodells dient. Wie ich bereits erwähnt habe, müssen wir nur zwei Methoden überschreiben UID-Dokument Unterklasse, (1) loadFromContents: ofType: Fehler: und 2) contentsForType: Fehler:. Die erste Methode wird beim Öffnen eines Dokuments aufgerufen, während die zweite Methode beim Speichern eines Dokuments aufgerufen wird. Beide Methoden werden vom Betriebssystem aufgerufen. Wir müssen diese Methoden niemals direkt anrufen.
#import "BookmarkDocument.h" #import "Bookmark.h" #define kArchiveKey @ "Bookmark" @implementation BookmarkDocument @synthesize bookmark = _bookmark;
Lass mich dich durchgehen loadFromContents: ofType: Fehler:. Das erste Argument ist Inhalt vom Typ Ich würde
. Dies kann entweder eine Instanz von sein NSData
oder NSFileWrapper
. Letzteres gilt nur, wenn die Anwendung Dateipakete verwendet. In unserem Fall können wir eine erwarten NSData
Beispiel. Wir prüfen zunächst, ob die Länge der NSData
Instanz ist nicht gleich Null. Wir initialisieren eine Instanz von NSKeyedUnarchiver
und liefern Sie es mit Inhalt Objekt. Durch die Dekodierung der Daten erhalten wir eine Instanz von Lesezeichen
Klasse zurück. Dies ist der Grund warum Lesezeichen
Klasse entspricht der NSCoding
Protokoll. Wenn die Länge der NSData
Instanz gleich Null ist, initialisieren wir ein neues Lesezeichen mit Standardwerten für Name und URL. Beachten Sie, dass wir zurückkehren JA
am Ende der Methode.
- (BOOL) loadFromContents: (id) Inhalt vonType: (NSString *) TypName Fehler: (NSError * __ Autoreleasing *) outError if ([Inhaltslänge]> 0) NSKeyedUnarchiver * unarchiver = [[NSKeyedUnarchiver-Zuordnung] initForReadingWithData: contents]; self.bookmark = [unarchiver decodeObjectForKey: kArchiveKey]; [unarchiver finishDecoding]; else self.bookmark = [[Zuordnen von Lesezeichen] initWithName: @ "Lesezeichen Name" andURL: @ "www.example.com"]; JA zurückgeben;
Das contentsForType: Fehler: Methode macht das Gegenteil. Das heißt, wir liefern die Daten, die auf die Festplatte geschrieben werden müssen. Dieses Datenobjekt ist die sogenannte Momentaufnahme unserer Modelldaten. Wir machen dies, indem wir eine Instanz von NSMutableData
und verwenden Sie diese zum Initialisieren einer Instanz von NSKeyedArchiver
. Dann können wir unsere Lesezeicheninstanz archivieren, damit sie auf die Festplatte geschrieben werden kann. Diese Methode erwartet, dass wir eine Instanz von zurückgeben NSData
und genau das tun wir. Unsere UID-Dokument
Die Unterklasse kann jetzt verwendet werden.
- (id) contentsForType: (NSString *) typeName-Fehler: (NSError * __ Autoreleasing *) outError NSMutableData * data = [[NSMutableData-Zuordnung] init]; NSKeyedArchiver * archiver = [[NSKeyedArchiver-Zuordnung] initForWritingWithMutableData: data]; [Archivierer encodeObject: self.bookmark forKey: kArchiveKey]; [archiver finishEncoding]; Daten zurückgeben;
Es gibt vier Elemente unserer Anwendung, die überarbeitet werden müssen, wenn iCloud Document Storage verwendet werden soll:
(1) Laden, (2) Anzeigen, (3) Speichern und (4) Löschen von Lesezeichen. Beginnen wir mit dem Laden von Lesezeichen.
Bevor wir uns das ansehen loadBookmarks Methode müssen wir eine private Eigenschaft, eine Instanz von NSMetadataQuery
. Es wird klar, warum wir dies in wenigen Minuten tun müssen. Vergessen Sie nicht, der Implementierungsdatei unseres View-Controllers zwei zusätzliche Importanweisungen hinzuzufügen, eine für die Lesezeichen
Klasse und eine für die BookmarkDocument
Klasse.
#import "ViewController.h" #import "Bookmark.h" #import "BookmarkDocument.h" #import "AddBookmarkViewController.h" @interface ViewController () NSMetadataQuery * _query; @ property (nichtatomisch, stark) NSMetadataQuery * query; @ende @implementation ViewController @synthesize bookmarks = _bookmarks; @synthesize tableView = _tableView; @synthesize query = _query;
Anstatt NSDictionary
Instanzen, unser Lesezeichen-Array, enthält die Datenquelle unserer Tabellenansicht Instanzen von BookmarkDocument
Klasse. Werfen wir einen Blick auf das Refactored loadBookmarks Methode. Wir beginnen mit der Initialisierung des Lesezeichen-Arrays. Als nächstes fragen wir NSFileManager
für die URL des iCloud-Containers verwenden wir zum Speichern unserer Lesezeichen. Lassen Sie sich nicht von dem farbenfrohen Namen dieser Methode ablenken. URLForUbiquityContainerIdentifier: akzeptiert ein Argument, den Bezeichner des iCloud-Containers, auf den Sie zugreifen möchten. Durch die Übergabe von Null als Argument, NSFileManager
wählt automatisch den ersten iCloud-Container aus, der in der Berechtigungsdatei unserer Anwendung deklariert ist. Wenn Sie eine iCloud-Container-ID angeben, müssen Sie auch die Team-ID angeben. Das richtige Format ist
- (void) loadBookmarks if (! self.bookmarks) self.bookmarks = [[NSMutableArray-Zuordnung] init]; NSURL * baseURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil]; if (baseURL) self.query = [[NSMetadataQuery-Zuordnung] init]; [self.query setSearchScopes: [NSArray arrayWithObject: NSMetadataQueryUbiquitousDocumentsScope]]; NSPredicate * predicate = [NSPredicate predicateWithFormat: @ "% K wie '*'", NSMetadataItemFSNameKey]; [self.query setPredicate: prädikat]; NSNotificationCenter * nc = [NSNotificationCenter defaultCenter]; [nc addObserver: Selbstselektor: @selector (queryDidFinish :) Name: NSMetadataQueryDidFinishGatheringNotification-Objekt: self.query]; [nc addObserver: Selbstselektor: @selector (queryDidUpdate :) Name: NSMetadataQueryDidUpdateNotification-Objekt: self.query]; [self.query startQuery];
Diese Methode dient nicht nur dazu, herauszufinden, wo wir unsere iCloud-Dokumente speichern können. Wenn Sie diese Methode erfolgreich aufrufen, erweitert das Betriebssystem die Sandbox unserer Anwendung um das von uns angegebene iCloud-Containerverzeichnis. Das bedeutet, dass wir diese Methode aufrufen müssen, bevor Daten in dieses Verzeichnis geschrieben oder gelesen werden können. Wenn Sie die zurückgegebene URL in der Konsole protokollieren würden, würden Sie zwei Merkwürdigkeiten feststellen: (1) Die zurückgegebene URL für den iCloud-Container ist eine lokale URL (befindet sich auf dem Gerät selbst) und (2) diese lokale URL ist nicht aktiv in der Sandbox unserer Anwendung. Die Funktionsweise von iCloud besteht darin, dass wir die Dokumente, die wir in iCloud speichern möchten, in diesem lokalen Verzeichnis speichern NSFileManager
bietet uns. Der iCloud-Daemon, der auf unserem Gerät im Hintergrund ausgeführt wird, kümmert sich um den Synchronisationsaspekt der Dokumente. Dies geschieht auch dann, wenn unsere Anwendung nicht ausgeführt wird.
Da sich die lokale URL außerhalb der Sandbox unserer Anwendung befindet, müssen Sie diese Methode aufrufen, bevor Sie dieses Verzeichnis lesen oder in dieses schreiben. Wenn Sie diese Methode aufrufen, bitten wir das Betriebssystem um Erlaubnis zum Lesen und Schreiben in dieses Verzeichnis.
Lass uns weiter das Sezieren loadBookmarks Methode. Wir überprüfen, ob die URL, von der wir zurückkommen, vorliegt NSFileManager
ist nicht gleich null. Letzteres impliziert zwei wichtige Dinge: (1) Wir haben einen Ort, an dem wir lesen und schreiben können, und (2) iCloud ist auf dem Gerät aktiviert. Der zweite Punkt ist besonders wichtig, da nicht bei allen Geräten iCloud aktiviert ist.
Ob NSFileManager
Haben Sie tatsächlich eine gültige URL zurückgegeben, initialisieren wir eine Instanz von NSMetadataQuery
und weisen Sie es der zuvor deklarierten Instanzvariablen zu. Das NSMetadataQuery
Mit dieser Klasse können wir den iCloud-Container nach Dokumenten durchsuchen. Nach dem Initialisieren einer Instanz von NSMetadataQuery
, Wir geben den Umfang unserer Suche an. In unserem Fall suchen wir im Unterlagen Verzeichnis unseres iCloud-Containers, da hier die Lesezeichen-Dokumente gespeichert werden. Sie können die Abfrage verfeinern, indem Sie ein Suchprädikat festlegen. Wenn Sie mit Core Data vertraut sind, ist dies für Sie nicht neu. Unsere Suche wird einfach sein, wir werden nach allen Dokumenten im Dokumentenverzeichnis unseres iCloud-Containers suchen, daher das Sternchen im Prädikat.
Bevor wir mit der Abfrage beginnen, ist es wichtig zu wissen, dass wir von unserer Abfrage kein sofortiges Ergebnis erwarten dürfen. Stattdessen registrieren wir unseren View Controller als Beobachter für die NSMetadataQueryDidUpdateNotification
und NSMetadataQueryDidFinishGatheringNotification
Benachrichtigungen mit unserer Abfrageinstanz als Absender. Dies bedeutet, dass wir benachrichtigt werden, wenn unsere Abfrage Ergebnisse zurückgegeben hat oder wenn die Ergebnisse aktualisiert wurden. Zum Schluss starten wir die Abfrage.
Es ist wichtig, dass wir einen Verweis auf die Abfrageinstanz behalten, um zu verhindern, dass sie freigegeben wird. Dies ist der Grund dafür, dass unser View Controller einen Verweis auf die Abfrage (als Instanzvariable) enthält, solange die Abfrage ausgeführt wird.
Werfen wir einen Blick auf die queryDidFinish: und queryDidUpdate: Benachrichtigungsrückrufmethoden, um zu erfahren, wie die Ergebnisse der Abfrage verarbeitet werden. Beide Methoden übergeben das Benachrichtigungsobjekt, das NSMetadataQuery
zu einer bequemen Methode, processQueryResults:. Wenn wir diese Methode betrachten, sehen wir, dass wir zunächst die Aktualisierungen für die Abfrage deaktivieren. Dies ist wichtig, da die Ergebnisse der Abfrage Live-Aktualisierungen erhalten können, wenn Änderungen vorgenommen werden. Dies muss verhindert werden, solange die Ergebnisse der Abfrage verarbeitet werden. Als Nächstes entfernen wir alle Objekte aus unserem Lesezeichen-Array und listen die Ergebnisse der Abfrage auf. Jedes Element im Ergebnisfeld ist eine Instanz von NSMetadataItem
, Diese enthält die Metadaten, die jedem Lesezeichen-Dokument zugeordnet sind, einschließlich der Datei-URL, die zum Öffnen des Dokuments erforderlich ist. Wir fragen jedes Metadatenelement nach der Datei-URL und initialisieren das entsprechende Dokument.
Beachten Sie, dass das Initialisieren eines Lesezeichen-Dokuments nicht bedeutet, dass wir es von der Festplatte geladen haben. Denken Sie daran, dass dies geschieht, indem Sie unserem Bookmark-Dokument eine Nachricht von senden openWithCompletionHandler:. Wenn der Öffnungsvorgang erfolgreich ist und das Dokument geladen ist, fügen wir es unserem Lesezeichen-Array hinzu und zeigen es in der Tabellenansicht an. Schließlich müssen wir unseren View-Controller als Beobachter entfernen, da wir an dieser Stelle keine Benachrichtigungen mehr erhalten müssen.
- (void) queryDidFinish: (NSNotification *) Benachrichtigung NSMetadataQuery * Abfrage = [Benachrichtigungsobjekt]; // Updates stoppen [Abfrage disableUpdates]; // Abfrage stoppen [Abfrage StopQuery]; // Lesezeichen löschen [self.bookmarks removeAllObjects]; [query.results enumerateObjectsUsingBlock: ^ (id obj, NSUInteger idx, BOOL * stop) NSURL * documentURL = [(NSMetadataItem *) obj valueForAttribute: NSMetadataItemURLKey]; BookmarkDocument * document = [[BookmarkDocument-Zuordnung] initWithFileURL: documentURL]; [document openWithCompletionHandler: ^ (BOOL-Erfolg) if (Erfolg) [self.bookmarks addObject: document]; [self.tableView reloadData]; ]; ]; [[NSNotificationCenter defaultCenter] removeObserver: self];
Der Code zum Anzeigen der Lesezeichen in unserer Tabellenansicht muss nicht viel geändert werden. Anstatt das Richtige zu holen NSDictionary
Instanz aus der Datenquelle holen wir eine Instanz von BookmarkDocument
Klasse. Der Zugriff auf den Namen und die URL des Lesezeichens muss ebenfalls aktualisiert werden.
- (UITableViewCell *) tableView: (UITableView *) aTableView cellForRowAtIndexPath: (NSIndexPath *) indexPath statischer NSString * CellIdentifier = @ "Cell Identifier"; UITableViewCell * cell = [aTableView dequeueReusableCellWithIdentifier: CellIdentifier]; if (cell == nil) cell = [[UITableViewCell-Zuweisung] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: CellIdentifier]; // Fetch Bookmark BookmarkDocument * document = [self.bookmarks objectAtIndex: indexPath.row]; // Zelle konfigurieren cell.textLabel.text = document.bookmark.name; cell.detailTextLabel.text = document.bookmark.url; zurück Zelle;
Geh rüber zum sparen: Methode in AddBookmarkViewController. Anstatt eine zu erstellen NSDictionary
und senden Sie es an unseren Main View Controller. Wir erstellen einen neuen Lesezeichen
Beispiel. Das ist es. Der Rest wird in der erledigt saveBookmark: Methode unseres Main View Controllers. Vergessen Sie nicht, eine Importanweisung für die Lesezeichen
Klasse.
- (IBAction) save: (id) sender Bookmark * bookmark = [[Zuordnen von Lesezeichen] initWithName: self.nameField.text undURL: self.urlField.text]; [self.viewController saveBookmark: Lesezeichen]; [self dismissViewControllerAnimated: YES Completion: nil];
Das Speichern eines Lesezeichens in unserem iCloud-Container ist fast so einfach wie das Speichern in der Sandbox unserer Anwendung. Zuerst fragen wir NSFileManager
für die URL unseres iCloud-Containers wie zuvor. Basierend auf dieser URL erstellen wir die richtige URL zum Speichern des Lesezeichendokuments in der Unterlagen Verzeichnis des iCloud-Containers. Der Name unseres Dokuments kann beliebig sein, solange es eindeutig ist. Ich habe mich entschieden, den Namen des Lesezeichens und einen Zeitstempel zu verwenden. Der Benutzer sieht diesen Dateinamen nicht, daher ist der Name nicht so wichtig. Wichtig ist, dass es einzigartig ist.
Wir haben eine Lesezeicheninstanz, aber noch kein Lesezeichendokument. Wir erstellen ein neues Lesezeichen-Dokument, indem wir es mit der gerade erstellten URL initialisieren. Als Nächstes weisen wir unser neues Lesezeichen der Lesezeicheneigenschaft des Dokuments zu. Schließlich fügen wir das Dokument dem Lesezeichen-Array hinzu und laden die Tabellenansicht erneut.
Das Speichern des Dokuments im iCloud-Container ist einfach. Wir starten den Sicherungsvorgang, über den ich zuvor gesprochen habe, indem wir unserem neuen Dokument die Nachricht senden saveToURL: forSaveOperation: completionHandler:. Der zweite Parameter dieser Methode gibt den Typ des Sicherungsvorgangs an. In unserem Fall passieren wir UIDocumentSaveForCreating
, Dies bedeutet, ein brandneues Lesezeichen-Dokument zu erstellen. Da wir in unserem Beispiel nichts Besonderes tun müssen, protokollieren wir einfach eine Nachricht an der Konsole, wenn der Speichervorgang abgeschlossen ist.
Möglicherweise haben Sie festgestellt, dass sich unsere Methodendeklaration geringfügig geändert hat. Wir übergeben keine Instanz mehr von NSDictionary
als einziges Argument. Stattdessen übergeben wir eine Instanz von Lesezeichen
Klasse. Stellen Sie sicher, dass Sie die Headerdatei aktualisieren, um diese Änderung zu berücksichtigen. Sie müssen außerdem eine Vorwärtsklassendeklaration hinzufügen, um zu verhindern, dass Compiler-Warnungen angezeigt werden. Dies sind Aufgaben, die Sie jetzt kennen sollten.
- (void) saveBookmark: (Lesezeichen *) Lesezeichen // Save Bookmark NSURL * baseURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil]; if (baseURL) NSURL * documentsURL = [baseURL URLByAppendingPathComponent: @ "Documents"]; NSURL * documentURL = [documentsURL URLByAppendingPathComponent: [NSString stringWithFormat: @ "Lesezeichen _% @ -% f", bookmark.name, [[Datumsdatum] timeIntervalSince1970]]; BookmarkDocument * document = [[BookmarkDocument-Zuordnung] initWithFileURL: documentURL]; document.bookmark = Lesezeichen; // Lesezeichen zu Lesezeichen hinzufügen [self.bookmarks addObject: document]; // Reload Table View [self.tableView reloadData]; [document saveToURL: documentURL forSaveOperation: UIDocumentSaveForCreating completionHandler: ^ (BOOL-Erfolg) if (Erfolg) NSLog (@ "Speichern erfolgreich."); else NSLog (@ "Speichern fehlgeschlagen."); ];
Der letzte fehlende Teil des Puzzles ist das Löschen von Lesezeichen. Dies ist im Vergleich zu dem, was wir bisher gemacht haben, sehr einfach. Wir holen das richtige Lesezeichen-Dokument aus der Datenquelle und teilen es mit NSFileManager
um es aus dem iCloud-Container zu löschen, indem Sie die korrekte URL übergeben. Dadurch wird das Dokument auch in iCloud gelöscht. So einfach ist es. Natürlich aktualisieren wir auch die Datenquelle und die Tabellensicht.
- (void) tableView: (UachableView *) aTableView commitEditingStyle: (UITableViewCellEditingStyle) EditingStyle forRowAtIndexPath: (NSIndexPath *) ; // Dokument löschen NSError * error = nil; if (! [[NSFileManager defaultManager] removeItemAtURL: document.fileURL Fehler: & Fehler]) NSLog (@ "Beim Versuch, ein Dokument zu löschen, ist ein Fehler aufgetreten. Fehler% @ mit Benutzerinfo% @.", Fehler, error.userInfo); // Update Bookmarks [self.bookmarks removeObjectAtIndex: indexPath.row]; // Tabellenansicht aktualisieren [aTableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: indexPath] withRowAnimation: UITableViewRowAnimationFade];
In diesem Lernprogramm haben wir unsere Anwendung überarbeitet, um iCloud Document Storage anstelle von iCloud Key Value Storage zu verwenden. Obwohl wir einiges an Code ü