Travailler avec iCloud Stockage de documents

Garder les données des applications synchronisées sur tous les appareils est une tâche complexe et ardue. Heureusement, c’est précisément pourquoi Apple a construit iCloud. Dans cette série Tuts + Premium, vous apprendrez le fonctionnement de iCloud et comment vos applications peuvent partager des données en toute transparence sur plusieurs appareils..


Aussi disponible dans cette série:

  1. Travailler avec iCloud: Introduction
  2. Travailler avec iCloud: Stockage de valeurs clés
  3. Travailler avec iCloud: Stockage de documents
  4. Travailler avec iCloud: Intégration des données de base

Dans le deuxième volet de cette série, je vous ai montré comment utiliser le stockage clé-valeur d'iCloud pour conserver la synchronisation de petites quantités de données utilisateur sur plusieurs périphériques. Même si Key-Value Storage est facile à utiliser et à adopter, l'un des inconvénients est la limitation qu'il impose à la quantité de données pouvant être stockée. N'oubliez pas que chaque application ne peut stocker que 1 Mo de données et que le nombre de paires clé-valeur est limité à 1024. Comme je l'ai mentionné à la fin du didacticiel précédent, notre gestionnaire de favoris peut rencontrer cette limitation si l'un de nos utilisateurs souhaite stocker beaucoup de marque-pages.

La solution à ce problème consiste à passer d'iCloud Key-Value Storage à iCloud Document Storage pour stocker les signets. En termes d'espace disque, iCloud Document Storage n'est limité que par le stockage iCloud de l'utilisateur. Sachant qu'un compte gratuit comprend 5 Go de stockage de données, iCloud Document Storage est la solution idéale pour notre gestionnaire de signets. Dans ce didacticiel, nous allons restructurer le gestionnaire de favoris de l'utilisation d'iCloud Key-Value Storage pour adopter iCloud Document Storage..


Avant de commencer

Je tiens à souligner qu’il est important que vous ayez lu les premier et deuxième épisodes de cette série avant de lire cet article. Dans ce tutoriel, nous allons refactoriser notre gestionnaire de favoris en nous appuyant sur les bases que nous avons posées dans la deuxième partie de la série..


Quelques mots à propos de UIDocument

Avec l’introduction d’iCloud, Apple a également pu UIDocument disponible pour les développeurs. Les ingénieurs chez Apple ont créé UIDocument en pensant à iCloud. UIDocument facilite l’intégration iCloud pour les applications basées sur des documents. Cependant, il est important de noter que UIDocument fait beaucoup plus que fournir une API facile à utiliser pour l'intégration iCloud.

Les applications basées sur des documents doivent faire face à de nombreux défis, tels que (1) lire et écrire des données depuis et sur un disque sans bloquer l'interface utilisateur, (2) enregistrer des données sur disque à des intervalles appropriés, et (3) s'intégrer éventuellement à iCloud. UIDocument fournit des solutions intégrées à ces défis.

Avant de commencer à travailler avec UIDocument, Je veux préciser ce que UIDocument est et ce que ce n'est pas. UIDocument est un objet contrôleur qui gère un ou plusieurs modèles de la même manière que UIViewController contrôle et gère une ou plusieurs vues. UIDocument ne stocke aucune donnée, mais gère les objets de modèle qui contiennent les données de l'utilisateur. C’est un concept important à comprendre, qui deviendra plus clair lorsque nous commencerons à refactoriser notre application pour l’utiliser. UIDocument.

Un autre concept important à comprendre est le fonctionnement des opérations de lecture et d’écriture lors de l’utilisation de UIDocument. Si vous décidez d'utiliser UIDocument dans votre application, vous n'avez pas à craindre de bloquer le thread principal lors de la lecture ou de l'écriture de données sur le disque. Lors de l'utilisation UIDocument, le système d'exploitation gérera automatiquement un certain nombre de tâches dans une file d'attente en arrière-plan et veillera à ce que le thread principal reste réactif. J'aimerais prendre un moment pour expliquer chaque opération plus en détail afin de vous donner une bonne compréhension des différentes pièces mobiles impliquées..

Commençons par lire les données du disque. L’opération de lecture commence par une opération d’ouverture lancée sur la file d’appel. L’opération d’ouverture est lancée lorsqu’un document est ouvert en lui envoyant un message de openWithCompletionHandler:. Nous transmettons un gestionnaire d'achèvement qui est appelé lorsque l'opération de lecture complète est terminée. C'est un aspect important des opérations de lecture et d'écriture. La lecture ou l'écriture des données depuis ou vers le disque peut prendre une quantité de temps non négligeable, et nous ne souhaitons pas le faire sur le thread principal et bloquer l'interface utilisateur. L’opération de lecture s’effectue dans une file d’arrière-plan gérée par le système d’exploitation. Lorsque l'opération de lecture est terminée, le loadFromContents: ofType: error: La méthode est appelée sur le document. Cette méthode envoie UIDocument les données nécessaires pour initialiser le (s) modèle (s) qu’il gère. Le gestionnaire d'achèvement est appelé à la fin de ce processus, ce qui signifie que nous pouvons répondre au chargement du document en mettant par exemple à jour l'interface utilisateur avec le contenu du document..


L'opération d'écriture est similaire. Il commence par une opération de sauvegarde lancée dans la file d’appel en envoyant saveToURL: forSaveOperation: completionHandler: à l'objet de document. Comme pour l'opération de lecture, nous transmettons un gestionnaire d'achèvement qui est appelé à la fin de l'opération d'écriture. L'écriture de données sur le disque s'effectue dans une file d'attente en arrière-plan. Le système d'exploitation demande UIDocument pour obtenir un instantané de ses données de modèle en lui envoyant un message de contentsForType: error:. Le gestionnaire d'achèvement est appelé à la fin de l'opération d'écriture, ce qui nous permet de mettre à jour l'interface utilisateur..


UIDocument est une classe de base et n'est pas destiné à être utilisé directement. Nous avons besoin de sous-classe UIDocument et l'adapter à nos besoins. En d'autres termes, nous sous-classe UIDocument afin qu’il connaisse notre modèle et sa gestion. Dans sa forme la plus fondamentale, le sous-classement UIDocument nous oblige seulement à passer outre loadFromContents: ofType: error: pour lire et contentsForType: error: pour écrire.

Confus? Tu devrais être. Même si UIDocument rend la vie beaucoup plus facile, c’est une classe avancée et nous traitons d’un sujet complexe. Cependant, je suis convaincu que vous maîtriserez parfaitement les applications basées sur des documents lorsque notre application aura été refactorisée..

Avant de continuer, je tiens à préciser nos objectifs pour ce didacticiel. L'objectif principal est de refactoriser notre application pour utiliser iCloud Document Storage au lieu de iCloud Key-Value Storage. Cela signifie que nous allons utiliser UIDocument et sous-classe pour répondre à nos besoins. En outre, nous allons créer une classe de modèle personnalisée pour notre signet, qui sera utilisée et gérée par le UIDocument sous-classe.


Étape 1: Configuration des droits

Actuellement, notre application est configurée pour utiliser uniquement le stockage clé-valeur. Pour activer le stockage de documents, nous devons d’abord configurer les droits de nos applications. Ouvrez le Éditeur cible en sélectionnant notre application dans le Navigateur de projet et sélectionnez la seule cible dans la liste des cibles. dans le Les droits section, vous devriez voir Conteneurs iCloud au dessous de iCloud Key-Value Store. La liste à côté de Conteneurs iCloud est vide pour le moment. Cliquez sur le bouton plus au bas de la liste et vous verrez que Xcode crée pour vous un identifiant de conteneur iCloud qui correspond à l'identifiant de bundle de votre application..

Qu'est-ce qu'un conteneur iCloud? Comme son nom l'indique, il s'agit d'un conteneur dans le stockage de données iCloud de l'utilisateur. En spécifiant un (ou plusieurs) conteneur iCloud dans le fichier de droits de notre application, nous indiquons au système d'exploitation les conteneurs auxquels notre application a accès..



Étape 2: Création de la classe de signet

Dans le didacticiel précédent, nous avons stocké chaque signet en tant qu’instance de NSDictionary, mais ce n'est pas une bonne solution pour une application basée sur des documents. Au lieu de cela, nous allons créer une classe de signets personnalisée qui nous permettra d’archiver facilement ses données..

Créer un nouveau NSObject sous-classe en choisissant Fichier dans le menu, en sélectionnant Nouveau, et alors Fichier… . Sélectionner Cacao Touch dans le panneau de gauche et choisissez Classe Objective-C dans la liste des modèles à droite. Donnez à la classe un nom de Signet et assurez-vous que c'est une sous-classe de NSObject. Spécifiez où vous souhaitez enregistrer la nouvelle classe et appuyez sur Créer.



Dans le fichier d’en-tête de notre modèle, nous ajoutons les deux propriétés du modèle de marque-pages utilisé dans le didacticiel précédent, à savoir: prénom et un URL. Les deux propriétés sont des instances de NSString. Nous déclarons également un initialiseur désigné, qui prend un nom et une URL comme paramètres. Enfin, il est important de veiller à ce que notre Signet classe conforme à la NSCoding protocole.

 #importation  @interface Bookmark: NSObject  NSString * _name; NSString * _url;  @property (nonatomic, copy) NSString * name; @property (nonatomic, copy) NSString * url; - (id) initWithName: (NSString *) nom etURL: (NSString *) url; @fin

Dans le fichier d'implémentation de notre modèle, nous définissons d'abord deux constantes pour le nom et l'URL de notre signet. Ceci est une bonne pratique car cela minimisera le risque que nous utilisions mal les clés que nous utiliserons sous peu. Ensuite, nous implémentons notre méthode d'initialisation. Cette méthode est simple. Nous initialisons notre instance et attribuons le nom et l'URL à nos variables d'instance de signet..

L’important est de mettre en œuvre les méthodes requises pour que le Signet classe conforme à la NSCoding protocole. Si la NSCoding Comme le protocole est nouveau pour vous, je vous encourage à lire le Guide de programmation des archives et des sérialisations car il s’agit d’un sujet important pour tout développeur Cocoa-Touch. L'essentiel est que le NSCoding protocole nous permet d’archiver et de désarchiver facilement des instances du Signet classe.

 #import "Bookmark.h" #define kBookmarkName @ "Nom du signet" #define kBookmarkURL @ "URL du signet" @implementation Signet @synthesize nom = _name, url = _url; #pragma mark - #pragma mark Initialization - (id) initWithName: (NSString *) nom etURL: (NSString *) url self = [super init]; if (self) self.name = name; self.url = url;  retourner soi-même;  #pragma mark - #pragma mark Protocole NSCoding - (void) encodeWithCoder: (NSCoder *) codeur [coder encodeObject: self.name forKey: kBookmarkName]; [coder encodeObject: self.url forKey: kBookmarkURL];  - (id) initWithCoder: (NSCoder *) codeur self = [super init]; if (self! = nil) self.name = [coder decodeObjectForKey: kBookmarkName]; self.url = [coder decodeObjectForKey: kBookmarkURL];  retourner soi-même;  @fin

Étape 3: Sous-classer UIDocument

Sous-classement UIDocument n'est pas aussi difficile que vous pourriez le penser. Comme je l'ai mentionné plus tôt, il suffit de remplacer deux méthodes et de créer une propriété pour le modèle de signet qu'il gérera..

Créer une nouvelle classe comme nous l’avons fait pour notre Signet classe et lui donner un nom de BookmarkDocument. Assurez-vous qu'il s'agit d'une sous-classe de UIDocument. Dans le fichier d'en-tête de notre UIDocument sous-classe, nous ajoutons une déclaration avant pour le Signet classe et nous créons une propriété pour notre modèle de signet. N'oubliez pas de synthétiser des accesseurs pour cette propriété.

 #importation  @class Bookmark; @interface BookmarkDocument: UIDocument Bookmark * _bookmark;  @property (nonatomic, strong) Signet * signet; @fin

Dans le fichier d'implémentation, nous importons le fichier d'en-tête du Signet class et définissez une autre constante qui servira de clé pour archiver et désarchiver le modèle de signet. Comme je l’ai mentionné plus tôt, il suffit de remplacer deux méthodes dans le UIDocument sous-classe, (1) loadFromContents: ofType: error: et (2) contentsForType: error:. La première méthode sera invoquée à l'ouverture d'un document alors que la seconde sera invoquée lors de la sauvegarde d'un document. Les deux méthodes sont appelées par le système d'exploitation. Nous n'avons jamais besoin d'appeler ces méthodes directement.

 #import "BookmarkDocument.h" #import "Bookmark.h" #define kArchiveKey @ "Bookmark" @implementation BookmarkDocument @synthesize bookmark = _bookmark;

Laissez-moi vous guider loadFromContents: ofType: error:. Le premier argument est Contenu de type identifiant. Cela peut être soit une instance de NSData ou NSFileWrapper. Ce dernier n'est applicable que lorsque l'application utilise des packages de fichiers. Dans notre cas, nous pouvons nous attendre à un NSData exemple. Nous vérifions d’abord si la longueur du NSData instance n'est pas égal à zéro. Nous initialisons une instance de NSKeyedUnarchiver et le fournir avec le Contenu objet. En décodant les données, nous obtenons une instance du Signet classe de retour. C’est la raison pour laquelle le Signet classe conforme à la NSCoding protocole. Si la longueur de la NSData instance est égale à zéro, nous initialisons un nouveau signet avec des valeurs par défaut pour le nom et l'URL. Notez que nous revenons OUI à la fin de la méthode.

 - (BOOL) loadFromContents: (id) contenu deType: (NSString *) erreur typeName: (NSError * __ autoreleasing *) outError if ([longueur du contenu]> 0) NSKeyedUnarchiver * unarchiver = [[NSKeyedUnarchiver alloc]]; self.bookmark = [unarchiver decodeObjectForKey: kArchiveKey]; [unarchiver finishDecoding];  else self.bookmark = [[Allocation de signet]] initWithName: @ "Nom de signet" etURL: @ "www.exemple.com" "];  retourne OUI; 

le contentsForType: error: la méthode fait le contraire. C'est-à-dire que nous fournissons les données qui doivent être écrites sur le disque. Cet objet de données est ce que l'on appelle un instantané de nos données de modèle. Nous faisons cela en initialisant une instance de NSMutableData et l'utiliser pour initialiser une instance de NSKeyedArchiver. Nous pouvons ensuite archiver notre instance de signet afin qu'elle puisse être écrite sur le disque. Cette méthode s'attend à ce que nous retournions une instance de NSData et c'est exactement ce que nous faisons. Notre UIDocument la sous-classe est maintenant prête à être utilisée.

 - (id) contentsForType: (NSString *) erreur typeName: (NSError * __ autoreleasing *) outError NSMutableData * data = [[NSMutableData alloc] init]; NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData: data]; [archiver encodeObject: self.bookmark forKey: kArchiveKey]; [archiver finishEncoding]; renvoyer des données; 

Étape 4: Refactoring des contrôleurs de vue

Si vous souhaitez utiliser iCloud Document Storage, quatre éléments de notre application doivent être restructurés:
(1) chargement, (2) affichage, (3) sauvegarde et (4) suppression de signets. Commençons par charger des favoris.

Avant de jeter un oeil à la loadBookmarks méthode, nous devons déclarer une propriété privée, une instance de NSMetadataQuery. Nous comprendrons pourquoi nous devons le faire en quelques minutes seulement. N'oubliez pas d'ajouter deux instructions d'importation supplémentaires au fichier d'implémentation de notre contrôleur de vue, une pour Signet classe et un pour le BookmarkDocument classe.

 #import "ViewController.h" #import "Bookmark.h" #import "BookmarkDocument.h" #import "AddBookmarkViewController.h" @interface ViewController () NSMetadataQuery * _query;  @property (nonatomic, strong) NSMetadataQuery * query; @end @implementation ViewController @synthesize bookmarks = _bookmarks; @synthesize tableView = _tableView; @synthesize query = _query;

Étape 4A: Chargement des signets

Au lieu de NSDictionary instances, notre tableau de signets, la source de données de notre vue table contiendra des instances du BookmarkDocument classe. Jetons un coup d'oeil à la refactored loadBookmarks méthode. Nous commençons par initialiser le tableau de signets. Ensuite, nous demandons NSFileManager pour l'URL du conteneur iCloud, nous allons utiliser pour stocker nos signets. Ne soyez pas rebutés par le nom coloré de cette méthode. URLForUbiquityContainerIdentifier: accepte un argument, l'identifiant du conteneur iCloud auquel nous voulons avoir accès. En passant à zéro comme argument, NSFileManager sélectionnera automatiquement le premier conteneur iCloud déclaré dans le fichier de droits de notre application. Notez que si vous spécifiez un identifiant de conteneur iCloud, vous devez également fournir l'identifiant de l'équipe. Le format correct est ..

 - (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: prédicate]; NSNotificationCenter * nc = [NSNotificationCenter defaultCenter]; [nc addObserver: sélecteur automatique: @selector (queryDidFinish :) nom: objet NSMetadataQueryDidFinishGatheringNotification: self.query]; [nc addObserver: sélecteur automatique: @selector (queryDidUpdate :) nom: NSMetadataQueryDidUpdateNotification objet: self.query]; [self.query startQuery]; 

Cette méthode ne sert pas uniquement à savoir où nous pouvons stocker nos documents iCloud. En appelant avec succès cette méthode, le système d'exploitation étendra le sandbox de notre application pour inclure le répertoire de conteneur iCloud que nous avons spécifié. Cela signifie que nous devons appeler cette méthode avant de pouvoir commencer à lire ou à écrire des données dans ce répertoire. Si vous enregistrez l'URL renvoyée dans la console, vous remarquerez deux particularités: (1) l'URL renvoyée pour le conteneur iCloud est une URL locale (située sur le périphérique lui-même) et dans le bac à sable de notre application. ICloud fonctionne comme suit: nous stockons les documents que nous souhaitons stocker dans iCloud dans ce répertoire local: NSFileManager nous fournit. Le démon iCloud, qui s'exécute en arrière-plan sur notre appareil, se chargera de l'aspect synchronisation des documents, même si notre application ne fonctionne pas..

L'URL locale résidant en dehors du sandbox de notre application, nous devons appeler cette méthode avant de lire ou d'écrire dans ce répertoire. En appelant cette méthode, nous demandons au système d'exploitation l'autorisation de lire et d'écrire dans ce répertoire..

Continuons à disséquer le loadBookmarks méthode. Nous vérifions que l'URL que nous avons renvoyée NSFileManager n'est pas égal à zéro. Ce dernier point implique deux choses importantes: (1) nous avons un emplacement dans lequel nous pouvons lire et écrire et (2) iCloud est activé sur le périphérique. Le second point est particulièrement important car iCloud ne sera pas activé sur tous les appareils..

Si NSFileManager a effectivement renvoyé une URL valide, nous initialisons une instance de NSMetadataQuery et l'assigner à la variable d'instance déclarée précédemment. le NSMetadataQuery class nous permet de rechercher des documents dans le conteneur iCloud. Après avoir initialisé une instance de NSMetadataQuery, nous précisons l'étendue de notre recherche. Dans notre cas, nous allons chercher dans le Les documents répertoire de notre conteneur iCloud puisque c’est l’emplacement où nous allons stocker les documents favoris. Vous pouvez affiner la requête en définissant un prédicat de recherche. Si vous connaissez Core Data, ce n’est pas une nouveauté pour vous. Notre recherche sera simple, nous rechercherons tous les documents dans le répertoire des documents de notre conteneur iCloud, d’où l’astérisque dans le prédicat.

Avant de commencer notre requête, il est important de réaliser que nous ne devrions pas nous attendre à un résultat immédiat de notre requête. Au lieu de cela, nous enregistrerons notre contrôleur de vue en tant qu’observateur du NSMetadataQueryDidUpdateNotification et NSMetadataQueryDidFinishGatheringNotification notifications avec notre instance de requête en tant qu'expéditeur. Cela signifie que nous serons avertis lorsque notre requête aura renvoyé des résultats ou lorsque les résultats auront été mis à jour. Enfin, nous commençons la requête.

Il est important de conserver une référence à l'instance de requête pour empêcher sa publication. C’est la raison pour laquelle notre contrôleur de vue conserve une référence à la requête (en tant que variable d’instance) tant que la requête est en cours d’exécution..

Jetons un coup d'oeil au queryDidFinish: et queryDidUpdate: méthodes de rappel de notification pour voir comment gérer les résultats de la requête. Les deux méthodes transmettent l’objet émetteur de la notification, le NSMetadataQuery par exemple, à une méthode de commodité, processQueryResults:. Lorsque nous examinons cette méthode, nous constatons que nous commençons tout d'abord par désactiver les mises à jour de la requête. Cela est important car les résultats de la requête peuvent recevoir des mises à jour en direct lorsque des modifications sont apportées et nous devons empêcher cela tant que nous traitons les résultats de la requête. Ensuite, nous supprimons tous les objets de notre tableau de signets et énumérons les résultats de la requête. Chaque élément du tableau de résultats est une instance de NSMetadataItem, qui contient les métadonnées associées à chaque document favori, y compris l'URL du fichier dont nous avons besoin pour ouvrir le document. Nous demandons à chaque métadonnée l'URL du fichier et initialisons le document correspondant..

Notez que l’initialisation d’un signet ne signifie pas que nous l’avons chargé à partir du disque. Rappelez-vous que ceci est fait en envoyant à notre document favori un message de openWithCompletionHandler:. Si l'opération d'ouverture réussit et que le document est chargé, nous l'ajoutons à notre tableau de signets et l'afficherons dans la vue tabulaire. Enfin, nous devons supprimer notre contrôleur de vue en tant qu’observateur, car nous n’avons plus besoin de recevoir de notifications à ce stade..

 - (void) queryDidFinish: (NSNotification *) notification NSMetadataQuery * query = [objet de notification]; // Stop Updates [query disableUpdates]; // Stop Query [query stopQuery]; // Clear Bookmarks [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: ^ (succès BOOL) if (succès) [self.bookmarks addObject: document]; [self.tableView reloadData]; ]; ]; [[NSNotificationCenter defaultCenter] removeObserver: self]; 

Étape 4B: Affichage des signets dans la vue tableau

Le code pour afficher les signets dans notre vue tableau n'a pas besoin de beaucoup changer. Au lieu de chercher le bon NSDictionary instance de la source de données, nous allons chercher une instance du BookmarkDocument classe. L'accès au nom et à l'URL du signet doit également être mis à jour..

 - (UITableViewCell *) tableView: (UITableView *) aTableView cellForRowAtIndexPath: (NSIndexPath *) indexPath statique NSString * CellIdentifier = @ "Identificateur de cellule"; UITableViewCell * cell = [aTableView dequeueReusableCellWithIdentifier: CellIdentifier]; if (cell == nil) cell = [[UITableViewCell alloc]] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: CellIdentifier];  // Récupérer le signet BookmarkDocument * document = [self.bookmarks objectAtIndex: indexPath.row]; // Configure Cell cell.textLabel.text = document.bookmark.name; cell.detailTextLabel.text = document.bookmark.url; cellule de retour; 

Étape 4C: Enregistrer un signet

Dirigez-vous vers le enregistrer: méthode en AddBookmarkViewController. Au lieu de créer un NSDictionary et en l'envoyant à notre contrôleur de vue principale, nous créons un nouveau Signet exemple. C'est tout. Le reste est traité dans le saveBookmark: méthode de notre contrôleur de vue principale. N'oubliez pas d'ajouter une déclaration d'importation pour le Signet classe.

 - (IBAction) save: (id) expéditeur Bookmark * bookmark = [[Allocation de signet]] initWithName: self.nameField.text etURL: self.urlField.text]; [self.viewController saveBookmark: signet]; [auto-licenciement ViewControllerAnimated: YES complétion: nil]; 

Enregistrer un signet dans notre conteneur iCloud est presque aussi simple que de le sauvegarder dans le bac à sable de notre application. Tout d'abord, nous demandons NSFileManager pour l'URL de notre conteneur iCloud comme nous l'avons fait précédemment. Sur la base de cette URL, nous construisons l’URL correcte pour enregistrer le document de signet dans le répertoire. Les documents répertoire du conteneur iCloud. Le nom de notre document peut être celui que nous souhaitons, à condition que son nom soit unique. J'ai choisi d'utiliser le nom du signet et un horodatage. L'utilisateur ne verra pas ce nom de fichier, il n'est donc pas très important. Ce qui est important c'est que c'est unique.

Nous avons une instance de signet, mais nous n'avons pas encore de document de signet. Nous créons un nouveau document de signet en l'initialisant avec l'URL que nous venons de construire. Ensuite, nous affectons notre nouveau signet à la propriété de signet du document. Enfin, nous ajoutons le document au tableau des signets et rechargeons la vue tableau..

L'enregistrement du document dans le conteneur iCloud est simple. Nous avons lancé l'opération de sauvegarde dont j'ai parlé précédemment en envoyant le message à notre nouveau document. saveToURL: forSaveOperation: completionHandler:. Le deuxième paramètre de cette méthode spécifie le type d'opération de sauvegarde. Dans notre cas, nous passons UIDocumentSaveForCreating, ce qui signifie créer un tout nouveau document de signet. Comme nous n'avons rien de spécial à faire dans notre exemple, nous enregistrons simplement un message sur la console à la fin de l'opération de sauvegarde..

Vous avez peut-être remarqué que notre déclaration de méthode a légèrement changé. Nous ne passons plus une instance de NSDictionary comme seul argument. Au lieu de cela, nous passons une instance du Signet classe. Assurez-vous de mettre à jour le fichier d'en-tête pour refléter ce changement. Vous devrez également ajouter une déclaration de classe foward pour empêcher l’apparition des avertissements du compilateur. Ce sont des tâches que vous devriez déjà connaître..

 - (void) saveBookmark: (Signet *) signet // Enregistrer le signet 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 = signet; // Ajouter un signet aux signets [self.bookmarks addObject: document]; // Reload Table View [self.tableView reloadData]; [document saveToURL: documentURL forSaveOperation: UIDocumentSaveForCreating completionHandler: ^ (succès BOOL) if (succès) NSLog (@ "Sauvegarde réussie.");  else NSLog (@ "La sauvegarde a échoué."); ]; 

Étape 4D: Suppression des signets

La dernière pièce manquante du puzzle est la suppression de signets. C'est très facile comparé à ce que nous avons fait jusqu'à présent. Nous récupérons le bon signet dans la source de données et disons NSFileManager pour le supprimer du conteneur iCloud en passant l'URL correcte. Cela supprimera également le document sur iCloud. C'est aussi simple que cela. Bien sûr, nous mettons également à jour la source de données et la vue tableau.

 - (void) tableView: (UITableView *) aTableView commitEditingStyle: (UITOLE VIEWE) ; // Supprimer le document NSError * error = nil; if (! [[NSFileManager defaultManager] removeItemAtURL: erreur document.fileURL: & erreur]) NSLog (@ "Une erreur s'est produite lors de la tentative de suppression du document. Erreur% @ avec les informations utilisateur% @.", erreur, error.userInfo);  // Mettre à jour les signets [self.bookmarks removeObjectAtIndex: indexPath.row]; // Mise à jour de la vue de table [aTableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: indexPath] withRowAnimation: UITableViewRowAnimationFade]; 

Conclusion

Dans ce tutoriel, nous avons restructuré notre application pour utiliser iCloud Document Storage au lieu de iCloud Key-Value Storage. Même si nous avons restructuré pas mal de code, le processus était relativement simple. Nous avons maintenant une application basée sur les documents qui est beaucoup plus adaptée à la gestion de grandes quantités de données utilisateur. Les composants de base sont en place et l'extension de l'application nécessite peu d'effort de notre part. Notez que notre application est toujours une implémentation minim