Werken met iCloud documentopslag

Het bijhouden van toepassingsgegevens gesynchroniseerd tussen apparaten is een complexe en ontmoedigende taak. Gelukkig is dat precies waarom Apple iCloud heeft gebouwd. In deze Tuts + Premium-serie leert u hoe iCloud werkt en hoe uw applicaties naadloos gegevens kunnen delen op meerdere apparaten.


Ook verkrijgbaar in deze serie:

  1. Werken met iCloud: introductie
  2. Werken met iCloud: opslag van sleutel / waarde
  3. Werken met iCloud: documentopslag
  4. Werken met iCloud: integratie van kerngegevens

In de tweede aflevering van deze serie heb ik je laten zien hoe je de Key-Value-opslag van iCloud kunt gebruiken om kleine hoeveelheden gebruikersgegevens gesynchroniseerd over meerdere apparaten te houden. Hoewel Key-Value Storage gemakkelijk te gebruiken en te gebruiken is, is een van de nadelen de beperking die het stelt aan de hoeveelheid gegevens die kan worden opgeslagen. Houd er rekening mee dat elke toepassing slechts 1 MB aan gegevens kan opslaan en het aantal sleutel / waarde-paren is beperkt tot 1024. Zoals ik aan het einde van de vorige zelfstudie heb vermeld, kan onze bladwijzerbeheerder tegen deze beperking aanlopen als een van onze gebruikers deze wil opslaan veel bladwijzers.

De oplossing voor dit probleem is het overstappen van iCloud Key-Value Storage naar iCloud Document Storage voor het opslaan van bladwijzers. Qua schijfruimte wordt iCloud-documentopslag alleen beperkt door de iCloud-opslag van de gebruiker. Wetende dat een gratis account wordt geleverd met 5 GB aan gegevensopslag, is iCloud Document Storage de ideale oplossing voor onze bladwijzerbeheerder. In deze zelfstudie zullen we de bladwijzerbeheerder refactiveren van het gebruik van iCloud Key-Value Storage om iCloud Document Storage te gebruiken.


Voor we beginnen

Ik zou willen benadrukken dat het belangrijk is dat je de eerste en tweede aflevering in deze serie hebt gelezen voordat je dit stuk leest. In deze zelfstudie zullen we onze bladwijzermanager refactiveren door voort te bouwen op de basis die we in deel 2 van de serie hebben gelegd.


Een paar woorden over UIDocument

Met de introductie van iCloud heeft Apple ook gemaakt UIDocument beschikbaar voor ontwikkelaars. De ingenieurs van Apple hebben gemaakt UIDocument met iCloud in gedachten. UIDocument maakt iCloud-integratie voor op documenten gebaseerde applicaties veel eenvoudiger. Het is echter belangrijk om op te merken dat UIDocument doet veel meer dan een eenvoudig te gebruiken API voor iCloud-integratie.

Documentgebaseerde applicaties hebben te maken met een aantal uitdagingen, zoals (1) lezen en schrijven van gegevens van en naar schijf zonder de gebruikersinterface te blokkeren, (2) gegevens opslaan op schijf met geschikte intervallen, en (3) optioneel integreren met iCloud. UIDocument biedt ingebouwde oplossingen voor deze uitdagingen.

Voordat we gaan werken UIDocument, Ik wil duidelijk maken wat UIDocument is en wat het niet is. UIDocument is een controllerobject dat een of meer modellen beheert, net als UIViewController beheert en beheert een of meer weergaven. UIDocument slaat geen gegevens op, maar beheert de modelobjecten die de gegevens van de gebruiker bevatten. Dit is een belangrijk concept om te begrijpen, dat duidelijker wordt wanneer we onze toepassing beginnen te refactoren om te gebruiken UIDocument.

Een ander belangrijk begrip om te begrijpen is hoe lees- en schrijfbewerkingen werken tijdens het gebruik UIDocument. Als je besluit te gebruiken UIDocument in uw toepassing hoeft u zich geen zorgen te maken over het blokkeren van de hoofdthema bij het lezen of schrijven van gegevens naar schijf. Tijdens gebruik UIDocument, het besturingssysteem zal automatisch een aantal taken voor u in een achtergrondwachtrij afhandelen en ervoor zorgen dat de hoofdthread responsief blijft. Ik wil graag een moment nemen en elke operatie in meer detail uitleggen om je een goed begrip te geven van de verschillende bewegende delen die erbij betrokken zijn.

Laten we beginnen met het lezen van gegevens van schijf. De leesbewerking begint met een open bewerking die is gestart op de bellende wachtrij. De open bewerking wordt gestart wanneer een document wordt geopend door er een bericht van te verzenden openWithCompletionHandler:. We passeren een afhandelingsafhandeling die wordt aangeroepen wanneer de volledige leesbewerking is voltooid. Dit is een belangrijk aspect van de lees- en schrijfbewerkingen. Het kan een niet-triviale hoeveelheid tijd kosten om de gegevens van of naar schijf te lezen of te schrijven, en we willen dit niet doen op de hoofdthread en de gebruikersinterface blokkeren. De eigenlijke leesbewerking vindt plaats in een achtergrondwachtrij beheerd door het besturingssysteem. Wanneer de leesbewerking is voltooid, de loadFromContents: OfType: error: methode wordt genoemd in het document. Deze methode verzendt UIDocument de gegevens die nodig zijn om het (de) door hem beheerde model (len) te initialiseren. De voltooiingsbehandelaar wordt opgeroepen wanneer dit proces is voltooid, wat betekent dat we kunnen reageren op het laden van het document door bijvoorbeeld de gebruikersinterface bij te werken met de inhoud van het document.


De schrijfbewerking is vergelijkbaar. Het begint met een opslagbewerking die in de wachtrij is gestart door te verzenden saveToURL: forSaveOperation: completionHandler: naar het document-object. Net als bij de leesbewerking passeren we een voltooiingshandler die wordt aangeroepen wanneer de schrijfbewerking is voltooid. Het schrijven van gegevens naar schijf vindt plaats in een achtergrondwachtrij. Het besturingssysteem vraagt UIDocument voor een momentopname van de modelgegevens door er een bericht van te verzenden contentsForType: error:. De voltooiingsbehandelaar wordt opgeroepen wanneer de schrijfbewerking is voltooid, wat ons de mogelijkheid geeft om de gebruikersinterface bij te werken.


UIDocument is een basisklasse en is niet bedoeld om direct te worden gebruikt. We moeten subclass UIDocument en pas het aan onze behoeften aan. Met andere woorden, we subklasse UIDocument zodat het weet van ons model en hoe het te beheren. In de meest eenvoudige vorm, subclassering UIDocument vereist alleen dat we negeren loadFromContents: OfType: error: voor lezen en contentsForType: error: om te schrijven.

Verward? Dat zou je moeten zijn. Hoewel UIDocument maakt het leven veel gemakkelijker, het is een geavanceerde klas en we hebben te maken met een complex onderwerp. Ik ben er echter van overtuigd dat u een goed begrip zult krijgen van op documenten gebaseerde toepassingen zodra we onze aanvraag hebben herzien.

Voordat we verder gaan, wil ik duidelijk maken wat onze doelen voor deze tutorial zijn. Het primaire doel is om onze applicatie te refacteren om gebruik te maken van iCloud Document Storage in plaats van iCloud Key-Value Storage. Dit betekent dat we gebruik zullen maken van UIDocument en subklasse het om te voldoen aan onze behoeften. Daarnaast zullen we een aangepaste modelklasse maken voor onze bladwijzer die zal worden gebruikt en beheerd door de UIDocument subklasse.


Stap 1: rechten configureren

Momenteel is onze applicatie zo geconfigureerd dat alleen Key-Value Storage wordt gebruikt. Om Documentopslag in te schakelen, moeten we eerst de rechten van onze applicatie configureren. Open de Doel-editor door onze applicatie te selecteren in de Project Navigator en selecteer het enige doelwit uit de doelenlijst. In de rechten sectie, zou u moeten zien iCloud-containers beneden iCloud Key-Value Store. De lijst ernaast iCloud-containers is op dit moment leeg. Klik op de plusknop onder aan de lijst en u ziet dat Xcode een iCloud-containeridentifier voor u maakt die overeenkomt met de bundel-ID van uw appication.

Wat is een iCloud-container? Zoals de naam al aangeeft, is het een container in de iCloud-gegevensopslag van de gebruiker. Door een (of meer) iCloud-containers op te geven in het rechtenbestand van onze applicatie, vertellen we het besturingssysteem welke containers onze applicatie toegang heeft tot.



Stap 2: De bladwijzersklasse maken

In de vorige zelfstudie hebben we elke bladwijzer opgeslagen als een instantie van NSDictionary, maar dit is geen goede oplossing voor een op documenten gebaseerde applicatie. In plaats daarvan zullen we een aangepaste bladwijzerklasse maken waarmee we zijn gegevens eenvoudig kunnen archiveren.

Maak een nieuw NSObject subklasse door te kiezen het dossier uit het menu, selecteren nieuwe, en dan Het dossier… . kiezen Cocoa Touch van het linkerpaneel en kies Objectieve C-klasse uit de lijst met sjablonen aan de rechterkant. Geef de klas een naam van Bladwijzer en zorg ervoor dat het een subklasse van is NSObject. Geef op waar u de nieuwe klasse wilt opslaan en klik op creëren.



In het header-bestand van ons model voegen we de twee eigenschappen toe van het bladwijzersmodel dat we in de vorige zelfstudie hebben gebruikt, een naam en een URL. Beide eigenschappen zijn instanties van NSString. We geven ook een aangewezen initializer aan, die een naam en een URL als parameters gebruikt. Ten slotte is het belangrijk om ervoor te zorgen dat onze Bladwijzer klas voldoet aan de NSCoding protocol.

 #importeren  @interface Bladwijzer: NSObject  NSString * _name; NSString * _url;  @property (nonatomic, copy) NSString * naam; @property (nonatomic, copy) NSString * url; - (id) initWithName: (NSString *) naam andURL: (NSString *) url; @einde

In het implementatiebestand van ons model definiëren we eerst twee constanten voor de naam en URL van onze bladwijzer. Dit is een goede praktijk omdat het de kans dat we de sleutels die we binnenkort zullen gebruiken verkeerd zal typeren. Vervolgens implementeren we onze initialisatiemethode. Deze methode is eenvoudig. We initialiseren onze instantie en wijzen de naam en URL toe aan onze bladwijzerinstancevariabelen.

Het belangrijkste onderdeel is om de vereiste methoden te implementeren om de Bladwijzer klasse conform de NSCoding protocol. Als het NSCoding protocol is nieuw voor je, dan moedig ik je aan om de Programmagids Archieven en Serialisaties te lezen, omdat dit een belangrijk onderwerp is voor elke Cocoa-Touch-ontwikkelaar. De kern hiervan is dat de NSCoding protocol stelt ons in staat om eenvoudig archiverings- en unarchive exemplaren van de Bladwijzer klasse.

 #import "Bookmark.h" #define kBookmarkName @ "Bookmark Name" #define kBookmarkURL @ "Bookmark URL" @implementation Bookmark @synthesize name = _name, url = _url; #pragma mark - #pragma mark Initialisatie - (id) initWithName: (NSString *) naam andURL: (NSString *) url self = [super init]; if (self) self.name = naam; self.url = url;  terugkeer zelf;  #pragma mark - #pragma mark NSCoding Protocol - (void) encodeWithCoder: (NSCoder *) coder [coder encodeObject: self.name forKey: kBookmarkName]; [coder encodeObject: self.url forKey: kBookmarkURL];  - (id) initWithCoder: (NSCoder *) coder self = [super init]; if (self! = nil) self.name = [coder decodeObjectForKey: kBookmarkName]; self.url = [codeer decodeObjectForKey: kBookmarkURL];  terugkeer zelf;  @end

Stap 3: Subclassing van UIDocument

subclassing UIDocument is niet zo moeilijk als je zou denken. Zoals ik eerder al zei, hoeven we alleen maar twee methoden te overschrijven en een property te maken voor het bladwijzermodel dat het gaat beheren.

Maak een nieuwe klas, net zoals we deden voor onze Bladwijzer klasse en geef het een naam BookmarkDocument. Zorg ervoor dat het een subklasse is van UIDocument. In het headerbestand van onze UIDocument subklasse voegen we een forward-verklaring toe voor de Bladwijzer klasse en we maken een eigenschap voor ons bladwijzermodel. Vergeet niet om toegang te creëren voor deze woning.

 #importeren  @class Bookmark; @interface BookmarkDocument: UIDocument Bookmark * _bookmark;  @property (nonatomic, strong) Bladwijzer * bladwijzer; @einde

In het implementatiebestand importeren we het header-bestand van de Bladwijzer class en definieer een andere constante als de sleutel voor het archiveren en uitpakken van het bladwijzermodel. Zoals ik eerder al zei, hoeven we alleen maar twee methoden in de te vervangen UIDocument subklasse, (1) loadFromContents: OfType: error: en (2) contentsForType: error:. De eerste methode wordt aangeroepen wanneer we een document openen, terwijl de tweede methode wordt aangeroepen wanneer een document wordt opgeslagen. Beide methoden worden aangeroepen door het besturingssysteem. We hoeven deze mehods nooit rechtstreeks te noemen.

 #import "BladwijzerDocument.h" #import "Bladwijzer.h" #define kArchiveKey @ "Bladwijzer" @implementation BladwijzerDocument @synthetiseren bladwijzer = _bookmark;

Ik zal je er doorheen helpen loadFromContents: OfType: error:. Het eerste argument is inhoud van type ID kaart. Dit kan een instantie zijn van NSData of NSFileWrapper. Dit laatste is alleen van toepassing wanneer de applicatie bestandspakketten gebruikt. In ons geval kunnen we een verwachten NSData aanleg. We controleren eerst of de lengte van de NSData instantie is niet gelijk aan nul. We initialiseren een instantie van NSKeyedUnarchiver en lever het met de inhoud voorwerp. Door de gegevens te decoderen, krijgen we een exemplaar van de Bladwijzer les terug. Dit is de reden waarom de Bladwijzer klas voldoet aan de NSCoding protocol. Als de lengte van de NSData instantie is gelijk aan nul, we initialiseren een nieuwe bladwijzer met standaardwaarden voor naam en URL. Merk op dat we terugkeren JA aan het einde van de methode.

 - (BOOL) loadFromContents: (id) inhoud vanType: (NSString *) typeName error: (NSError * __ autoreleasing *) outError if ([contents length]> 0) NSKeyedUnarchiver * unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: contents]; self.bookmark = [unarchiver decodeObjectForKey: kArchiveKey]; [unarcheer finishDecoding];  else self.bookmark = [[Bookmark alloc] initWithName: @ "Bookmark Name" andURL: @ "www.example.com"];  return YES; 

De contentsForType: error: methode doet het tegenovergestelde. Dat wil zeggen dat we de gegevens leveren die naar de schijf moeten worden geschreven. Dit data-object is de zogenaamde snapshot van onze modelgegevens. We doen dit door een instance van te initialiseren NSMutableData en gebruik dit om een ​​instantie van te initialiseren NSKeyedArchiver. We kunnen dan onze bladwijzer-instantie archiveren zodat deze naar schijf kan worden geschreven. Deze methode verwacht dat we een instantie van. Retourneren NSData en dat is precies wat we doen. Onze UIDocument subklasse is nu klaar voor gebruik.

 - (id) contentForType: (NSString *) typeName error: (NSError * __ autoreleasing *) outError NSMutableData * data = [[NSMutableData alloc] init]; NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData: data]; [archiver encodeObject: self.bookmark forKey: kArchiveKey]; [archiver finishEncoding]; terugkeer van gegevens; 

Stap 4: Refactoring View Controllers

Er zijn vier elementen van onze applicatie die moeten worden aangepast als we gebruik willen maken van iCloud Document Storage:
(1) laden, (2) weergeven, (3) opslaan en (4) verwijderen van bladwijzers. Laten we beginnen met het laden van bladwijzers.

Voordat we naar de loadBookmarks methode, moeten we een privé-eigendom aangeven, een instantie van NSMetadataQuery. Het zal duidelijk worden waarom we dit binnen enkele minuten moeten doen. Vergeet niet om twee extra importinstructies toe te voegen aan het implementatiebestand van onze view controller, één voor de Bladwijzer klasse en één voor de BookmarkDocument klasse.

 msgstr "# import".  @property (nonatomic, strong) NSMetadataQuery * query; @end @implementation ViewController @synthetiseren bladwijzers = _bookmarks; @synthesize tableView = _tableView; @synthesize query = _query;

Stap 4A: Bladwijzers laden

In plaats van NSDictionary exemplaren, onze bladwijzerarray, de gegevensbron van onze tabelweergave bevat exemplaren van de BookmarkDocument klasse. Laten we eens kijken naar de gerefactureerde loadBookmarks methode. We beginnen met het initialiseren van de bladwijzerarray. Vervolgens vragen we NSFileManager voor de URL van de iCloud-container die we gebruiken om onze bladwijzers op te slaan. Laat je niet afschudden door de kleurrijke naam van deze methode. URLForUbiquityContainerIdentifier: accepteert één argument, de ID van de iCloud-container waartoe we toegang willen. Door nul als argument te negeren, NSFileManager selecteert automatisch de eerste iCloud-container die is gedeclareerd in het rechtenbestand van onze applicatie. Houd er rekening mee dat als u een iCloud-container-ID opgeeft, u ook de team-ID moet opgeven. Het juiste formaat is ..

 - (void) loadBookmarks if (! self.bookmarks) self.bookmarks = [[NSMutableArray alloc] init];  NSURL * baseURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil]; if (baseURL) self.query = [[NSMetadataQuery alloc] init]; [self.query setSearchScopes: [NSArray arrayWithObject: NSMetadataQueryUbiquitousDocumentsScope]]; NSPredicate * predicate = [NSPredicate predicateWithFormat: @ "% K like '*'", NSMetadataItemFSNameKey]; [self.query setPredicate: predicate]; NSNotificationCenter * nc = [NSNotificationCenter defaultCenter]; [nc addObserver: self selector: @selector (queryDidFinish :) naam: NSMetadataQueryDidFinishGatheringNotification-object: self.query]; [nc addObserver: self selector: @selector (queryDidUpdate :) naam: NSMetadataQueryDidUpdateNotification-object: self.query]; [self.query startQuery]; 

Deze methode is niet alleen om te achterhalen waar we onze iCloud-documenten kunnen opslaan. Door deze methode te gebruiken, breidt het besturingssysteem de sandbox van onze toepassing uit naar de door ons opgegeven iCloud-containerdirectory. Dit betekent dat we deze methode moeten gebruiken voordat we gegevens in deze map kunnen gaan lezen of schrijven. Als u de geretourneerde URL bij de console zou registreren, zou u twee eigenaardigheden opmerken: (1) de geretourneerde URL voor de iCloud-container is een lokale URL (die zich op het apparaat zelf bevindt) en (2) deze lokale URL leeft niet in de sandbox van onze applicatie. De manier waarop iCloud werkt, is dat we de documenten die we in iCloud willen opslaan in deze lokale map opslaan NSFileManager voorzie ons. De iCloud-daemon, die op de achtergrond op ons apparaat draait, zorgt voor het synchronisatieaspect van de documenten en zal dit ook doen als onze applicatie niet draait.

Omdat de lokale URL buiten de sandbox van onze toepassing leeft, moeten we deze methode gebruiken voordat we deze map lezen of ernaar schrijven. Door deze methode aan te roepen, vragen we het besturingssysteem toestemming om deze map te lezen en ernaar te schrijven.

Laten we doorgaan met het ontleden van de loadBookmarks methode. We verifiëren dat de URL waar we vandaan komen NSFileManager is niet gelijk aan nul. Dit laatste impliceert twee belangrijke dingen, (1) we hebben een locatie waar we van kunnen lezen en schrijven en (2) iCloud is ingeschakeld op het apparaat. Het tweede punt is vooral belangrijk omdat niet alle apparaten iCloud hebben ingeschakeld.

Als NSFileManager heeft inderdaad een geldige URL geretourneerd, we initialiseren een exemplaar van NSMetadataQuery en wijs het toe aan de instantievariabele die we eerder hebben verklaard. De NSMetadataQuery klasse stelt ons in staat om in de iCloud-container naar documenten te zoeken. Na het initialiseren van een instantie van NSMetadataQuery, we specificeren de reikwijdte van onze zoektocht. In ons geval zullen we zoeken in de documenten directory van onze iCloud-container, omdat dit de locatie is waar we de bladwijzerdocumenten opslaan. U kunt de query verfijnen door een zoekpredikaat in te stellen. Als u bekend bent met Core Data, dan is dit niet nieuw voor u. Onze zoekopdracht zal eenvoudig zijn, we zullen zoeken naar alle documenten in de documenten-directory van onze iCloud-container, vandaar de asterisk in het predicaat.

Voordat we aan onze vraag beginnen, is het belangrijk om te beseffen dat we geen onmiddellijk resultaat van onze vraag moeten verwachten. In plaats daarvan zullen we onze view controller registreren als waarnemer voor de NSMetadataQueryDidUpdateNotification en NSMetadataQueryDidFinishGatheringNotification Meldingen met onze query-instantie als de afzender. Dit betekent dat we op de hoogte worden gesteld wanneer onze query resultaten heeft opgeleverd of wanneer de resultaten zijn bijgewerkt. Eindelijk beginnen we de vraag.

Het is belangrijk dat we een verwijzing naar de query-instantie bijhouden om te voorkomen dat deze wordt vrijgegeven. Dit is de reden dat onze view-controller een verwijzing naar de query (als een instantievariabele) houdt zolang de query actief is.

Laten we eens kijken naar de queryDidFinish: en queryDidUpdate: callback-methoden voor kennis om te zien hoe de resultaten van de query moeten worden verwerkt. Beide methoden geven het afzenderobject van de melding door, het NSMetadataQuery bijvoorbeeld naar een gemaksmethode, processQueryResults:. Wanneer we deze methode bekijken, zien we dat we eerst beginnen met het uitschakelen van updates voor de query. Dit is belangrijk omdat de resultaten van de query live updates kunnen ontvangen wanneer er wijzigingen plaatsvinden en we dit moeten voorkomen zolang we de resultaten van de query verwerken. Vervolgens verwijderen we alle objecten uit onze bladwijzerarray en inventariseren we de resultaten van de query. Elk item in de resultatenarray is een instantie van NSMetadataItem, die de metadata bevat die geassocieerd zijn met elk bladwijzersdocument, inclusief de bestands-URL die we nodig hebben om het document te openen. We vragen elk metagegevensitem om de bestands-URL en initialiseren het betreffende document.

Merk op dat het initialiseren van een bladwijzersdocument niet betekent dat we het van de schijf hebben geladen. Vergeet niet dat dit is gebeurd door ons bladwijzerdocument een bericht te sturen van openWithCompletionHandler:. Als de open bewerking is geslaagd en het document is geladen, voegen we het toe aan onze reeks bladwijzers en geven dit weer in de tabelweergave. Ten slotte moeten we onze view controller als waarnemer verwijderen, omdat we op dit moment geen meldingen meer hoeven te ontvangen.

 - (void) queryDidFinish: (NSNotification *) notificatie NSMetadataQuery * query = [notification-object]; // Stop Updates [query disableUpdates]; // Stop Query [query stopQuery]; // Wis bladwijzers [self.bookmarks removeAllObjects]; [query.results enumerateObjectsUsingBlock: ^ (id obj, NSUInteger idx, BOOL * stop) NSURL * documentURL = [(NSMetadataItem *) obj valueForAttribute: NSMetadataItemURLKey]; BookmarkDocument * document = [[BookmarkDocument alloc] initWithFileURL: documentURL]; [document openWithCompletionHandler: ^ (BOOL-succes) if (succes) [self.bookmarks addObject: document]; [self.tableBekijk reloadData]; ]; ]; [[NSNotificationCenter defaultCenter] removeObserver: self]; 

Stap 4B: weergave van bladwijzers in de tabelweergave

De code voor het weergeven van de bladwijzers in onze tabelweergave hoeft niet veel te veranderen. In plaats van het juiste te halen NSDictionary bijvoorbeeld uit de gegevensbron, halen we een exemplaar van de BookmarkDocument klasse. Toegang tot de naam en URL van de bladwijzer moet ook worden bijgewerkt.

 - (UITableViewCell *) tableView: (UITableView *) aTableView cellForRowAtIndexPath: (NSIndexPath *) indexPath static NSString * CellIdentifier = @ "Cell Identifier"; UITableViewCell * cell = [aTableView dequeueReusableCellWithIdentifier: CellIdentifier]; if (cell == nil) cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: CellIdentifier];  // Bladwijzer toevoegen BladwijzerDocument * document = [object.inst.locaties objectAtIndex: indexPath.row]; // Configure Cell cell.textLabel.text = document.bookmark.name; cell.detailTextLabel.text = document.bookmark.url; terugkeer cel; 

Stap 4C: een bladwijzer opslaan

Ga naar de opslaan: methode in AddBookmarkViewController. In plaats van een NSDictionary en verzenden naar onze hoofdweergavecontroller, we maken een nieuwe Bladwijzer aanleg. Dat is het. De rest wordt behandeld in de saveBookmark: methode van onze hoofdweergavecontroller. Vergeet niet om een ​​importinstructie toe te voegen voor de Bladwijzer klasse.

 - (IBAction) opslaan: (id) afzender Bookmark * bookmark = [[Bookmark alloc] initWithName: self.nameField.text andURL: self.urlField.text]; [self.viewController saveBookmark: bookmark]; [self dismissViewControllerAnimated: YES completion: nil]; 

Het opslaan van een bladwijzer in onze iCloud-container is bijna net zo eenvoudig als het opslaan ervan in de sandbox van onze applicatie. Eerst vragen we NSFileManager voor de URL van onze iCloud-container zoals we eerder deden. Op basis van die URL construeren we de juiste URL voor het opslaan van het bladwijzerdocument in de documenten map van de iCloud-container. De naam van ons document kan zijn wat we willen dat het is, zolang de naam uniek is. Ik heb ervoor gekozen om de naam van de bladwijzer en een tijdstempel te gebruiken. De gebruiker ziet deze bestandsnaam niet, dus de naam is niet zo belangrijk. Wat belangrijk is, is dat het uniek is.

We hebben een bladwijzerinstantie, maar we hebben nog geen bladwijzerdocument. We maken een nieuw bladwijzerdocument door het te initialiseren met de URL die we zojuist hebben geconstrueerd. Vervolgens wijzen we onze nieuwe bladwijzer toe aan de bladwijzereigenschap van het document. Ten slotte voegen we het document toe aan de bladwijzerarray en herladen de tabelweergave.

Het opslaan van het document in de iCloud-container is eenvoudig. We initiëren de opslagbewerking waar ik het eerder over had, door ons nieuwe document het bericht te sturen saveToURL: forSaveOperation: completionHandler:. De tweede parameter van deze methode geeft het type opslagbewerking aan. In ons geval gaan we voorbij UIDocumentSaveForCreating, wat betekent dat je een gloednieuw bladwijzerdocument moet maken. Omdat we in ons voorbeeld niets speciaals hoeven te doen, loggen we gewoon een bericht in op de console wanneer de opslagbewerking is voltooid.

U hebt misschien gemerkt dat onze methodeverklaring enigszins is gewijzigd. We passeren niet langer een instantie van NSDictionary als het enige argument. In plaats daarvan geven we een instantie van de Bladwijzer klasse. Zorg ervoor dat u het headerbestand bijwerkt om deze wijziging te weerspiegelen. U moet ook een foward class-verklaring toevoegen om te voorkomen dat er compilerwaarschuwingen verschijnen. Dit zijn taken waar je nu al bekend mee zou moeten zijn.

 - (ongeldig) saveBookmark: (bladwijzer *) bladwijzer // bladwijzer opslaan NSURL * baseURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil]; if (baseURL) NSURL * documentsURL = [baseURL URLByAppendingPathComponent: @ "Documents"]; NSURL * documentURL = [documentsURL URLByAppendingPathComponent: [NSString stringWithFormat: @ "Bookmark _% -% f", bookmark.name, [[NSDate date] timeIntervalSince1970]]]; BookmarkDocument * document = [[BookmarkDocument alloc] initWithFileURL: documentURL]; document.bookmark = bladwijzer; // Voeg bladwijzer toe aan bladwijzers [self.bookmarks addObject: document]; // Reload Table View [self.tableView reloadData]; [document saveToURL: documentURL forSaveOperation: UIDocumentSaveForCreating completionHandler: ^ (BOOL-succes) if (succes) NSLog (@ "Save succeeded.");  else NSLog (@ "Opslaan mislukt."); ]; 

Stap 4D: Verwijzingen naar bladwijzers

Het laatste ontbrekende stukje van de puzzel is het verwijderen van bladwijzers. Dit is heel eenvoudig in vergelijking met wat we tot nu toe hebben gedaan. We halen het juiste bladwijzerdocument uit de gegevensbron en vertellen het NSFileManager om het uit de iCloud-container te verwijderen door de juiste URL door te geven. Hiermee wordt ook het document op iCloud verwijderd. Dat is hoe gemakkelijk het is. Natuurlijk werken we ook de gegevensbron en de tabelweergave bij.

 - (void) tableView: (UITableView *) aTableView commitEditingStyle: (UITableViewCellEditingStyle) editingStyle forRowAtIndexPath: (NSIndexPath *) indexPath if (editingStyle == UITableViewCellEditingStyleDelete) // Bladwijzer Bladwijzer ophalenDocument * document = [object self.bookmarks ObjectAtIndex: indexPath.row] ; // Verwijderen Document NSError * error = nil; if (! [[NSFileManager defaultManager] removeItemAtURL: document.fileURL error: & error]) NSLog (@ "Er is een fout opgetreden bij het verwijderen van het document. Fout% @ met gebruikersinfo% @.", error, error.userInfo);  // Bladwijzers bijwerken [self.bookmarks removeObjectAtIndex: indexPath.row]; // Tabelweergave bijwerken [aTableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: indexPath] withRowAnimation: UITableViewRowAnimationFade]; 

Conclusie

In deze zelfstudie hebben we onze applicatie aangepast om iCloud Document Storage te gebruiken in plaats van iCloud Key-Value Storage. Ook al hebben we behoorlijk wat code gerefactureerd, het proces was redelijk eenvoudig. We hebben nu een op documenten gebaseerde applicatie die veel geschikter is voor het verwerken van grotere hoeveelheden gebruikersgegevens. De basiscomponenten zijn aanwezig en het uitbreiden van de applicatie vereist weinig inspanning van onze kant. Merk op dat onze applicatie nog steeds een minimale implementatie is van een bladwijzermanager. Er is bijvoorbeeld geen optie om bladwijzers te bewerken. We zouden ook meer foutcontroles moeten uitvoeren als we onze applicatie willen omzetten in een robuuste en betrouwbare applicatie die klaar is om vrijgegeven te worden.

Je hebt misschien ook gemerkt dat we een aantal methoden hebben die we niet langer nodig hebben. Ik heb deze methoden uit het definitieve codevoorbeeld verwijderd en ik stel voor dat u hetzelfde doet. Het verwijderen van verouderde