Trabajando con iCloud Almacenamiento de documentos

Mantener los datos de la aplicación sincronizados entre dispositivos es una tarea compleja y desalentadora. Afortunadamente, esa es exactamente la razón por la que Apple construyó iCloud. En esta serie Tuts + Premium, aprenderá cómo funciona iCloud y cómo sus aplicaciones pueden compartir datos a la perfección en múltiples dispositivos.


También disponible en esta serie:

  1. Trabajando con iCloud: Introducción
  2. Trabajando con iCloud: Almacenamiento de valor-clave
  3. Trabajando con iCloud: Almacenamiento de documentos
  4. Trabajando con iCloud: Core Data Integration

En la segunda entrega de esta serie, le mostré cómo aprovechar Key-Value Storage de iCloud para mantener pequeñas cantidades de datos de usuarios sincronizados en múltiples dispositivos. A pesar de que Key-Value Storage es fácil de usar y adoptar, una de las desventajas es la limitación que plantea sobre la cantidad de datos que se pueden almacenar. Recuerde que cada aplicación solo puede almacenar 1 MB de datos y el número de pares clave-valor está limitado a 1024. Como mencioné al final del tutorial anterior, nuestro administrador de marcadores podría tener esta limitación si alguno de nuestros usuarios desea almacenar muchos marcadores.

La solución a este problema es cambiar de iCloud Key-Value Storage a iCloud Document Storage para almacenar marcadores. En términos de espacio en disco, iCloud Document Storage solo está limitado por el almacenamiento de iCloud del usuario. Sabiendo que una cuenta gratuita viene con 5GB de almacenamiento de datos, iCloud Document Storage es la solución ideal para nuestro administrador de marcadores. En este tutorial, vamos a refactorizar el administrador de marcadores de usar el almacenamiento de iCloud Key-Value para adoptar el almacenamiento de documentos de iCloud.


Antes que empecemos

Me gustaría enfatizar que es importante que haya leído la primera y la segunda entrega de esta serie antes de leer esta pieza. En este tutorial, refactorizaremos nuestro administrador de marcadores al construir sobre los cimientos que pusimos en la parte 2 de la serie..


Unas pocas palabras sobre UIDocumento

Con la introducción de iCloud, Apple también hizo. UIDocumento Disponible para desarrolladores. Los ingenieros de Apple crearon. UIDocumento con iCloud en mente. UIDocumento hace que la integración de iCloud para aplicaciones basadas en documentos sea mucho más fácil. Sin embargo, es importante tener en cuenta que UIDocumento hace mucho más que proporcionar una API fácil de usar para la integración de iCloud.

Las aplicaciones basadas en documentos deben enfrentar una serie de desafíos, como (1) leer y escribir datos desde y hacia el disco sin bloquear la interfaz de usuario, (2) guardar los datos en el disco a intervalos apropiados y (3) integrarse opcionalmente con iCloud. UIDocumento Proporciona soluciones integradas para estos desafíos..

Antes de empezar a trabajar con UIDocumento, Quiero aclarar que UIDocumento es y lo que no es. UIDocumento es un objeto controlador que administra uno o más modelos al igual que UIViewController Controla y gestiona una o más vistas.. UIDocumento no almacena ningún dato, pero administra los objetos del modelo que contienen los datos del usuario. Este es un concepto importante a entender, que se aclarará cuando comencemos a refactorizar nuestra aplicación para usarla. UIDocumento.

Otro concepto importante a entender es cómo funcionan las operaciones de lectura y escritura cuando se usa UIDocumento. Si decides utilizar UIDocumento en su aplicación, no tiene que preocuparse por bloquear el hilo principal al leer o escribir datos en el disco. Cuando usas UIDocumento, el sistema operativo manejará automáticamente una serie de tareas para usted en una cola en segundo plano y se asegurará de que el hilo principal siga respondiendo. Me gustaría tomarme un momento y explicar cada operación con más detalle para darle una buena comprensión de las diferentes partes móviles involucradas.

Vamos a empezar con la lectura de datos del disco. La operación de lectura comienza con una operación abierta iniciada en la cola de llamadas. La operación de apertura se inicia cuando se abre un documento enviándole un mensaje de openWithCompletionHandler:. Pasamos un controlador de finalización que se invoca cuando finaliza la operación de lectura completa. Este es un aspecto importante de las operaciones de lectura y escritura. Puede tomar una cantidad de tiempo no trivial leer o escribir los datos desde o hacia el disco, y no queremos hacer esto en el hilo principal y bloquear la interfaz de usuario. La operación de lectura real tiene lugar en una cola de fondo administrada por el sistema operativo. Cuando finaliza la operación de lectura, loadFromContents: ofType: error: El método se llama en el documento. Este método envía UIDocumento Los datos necesarios para inicializar los modelos que gestiona. El controlador de finalización se invoca cuando finaliza este proceso, lo que significa que podemos responder a la carga del documento, por ejemplo, actualizando la interfaz de usuario con el contenido del documento..


La operación de escritura es similar. Comienza con una operación de guardado iniciada en la cola de llamadas enviando saveToURL: forSaveOperation: completedHandler: al objeto de documento. Al igual que con la operación de lectura, pasamos un controlador de finalización que se invoca cuando finaliza la operación de escritura. La escritura de datos en el disco tiene lugar en una cola de fondo. El sistema operativo pregunta. UIDocumento para obtener una instantánea de los datos de su modelo enviándole un mensaje de contentsForType: error:. El controlador de finalización se invoca cuando finaliza la operación de escritura, lo que nos da la oportunidad de actualizar la interfaz de usuario.


UIDocumento es una clase base y no debe utilizarse directamente. Necesitamos subclases UIDocumento Y adaptarlo a nuestras necesidades. En otras palabras, nosotros subclase. UIDocumento Para que sepa sobre nuestro modelo y como gestionarlo. En su forma más básica, subclasificación. UIDocumento solo nos obliga a anular loadFromContents: ofType: error: para leer y contentsForType: error: para la escritura.

¿Confuso? Usted debería ser. Aunque UIDocumento hace la vida mucho más fácil, es una clase avanzada y estamos tratando un tema complejo. Sin embargo, estoy convencido de que obtendrá una buena comprensión de las aplicaciones basadas en documentos una vez que hayamos reformulado nuestra aplicación..

Antes de continuar, quiero aclarar cuáles son nuestros objetivos para este tutorial. El objetivo principal es refactorizar nuestra aplicación para utilizar iCloud Document Storage en lugar de iCloud Key-Value Storage. Esto significa que haremos uso de UIDocumento y subclase para que se ajuste a nuestras necesidades. Además, crearemos una clase de modelo personalizada para nuestro marcador que será utilizada y administrada por el UIDocumento subclase.


Paso 1: Configuración de los derechos

Actualmente, nuestra aplicación está configurada para usar solo Key-Value Storage. Para habilitar el almacenamiento de documentos, primero debemos configurar los derechos de nuestra aplicación. Abre el Editor de destino seleccionando nuestra aplicación en el Navegador de proyectos y seleccione el único objetivo de la lista de objetivos. En el Derechos sección, deberías ver Contenedores iCloud abajo iCloud Key-Value Store. La lista al lado de Contenedores iCloud está vacío en este momento. Haga clic en el botón más en la parte inferior de la lista y verá que Xcode crea un identificador de contenedor de iCloud para usted que coincide con el identificador del paquete de su aplicación..

¿Qué es un contenedor iCloud? Como su nombre lo indica, es un contenedor en el almacenamiento de datos de iCloud del usuario. Al especificar uno (o más) contenedores iCloud en el archivo de derechos de nuestra aplicación, le informamos al sistema operativo a qué contenedores tiene acceso nuestra aplicación..



Paso 2: Creando la Clase Bookmark

En el tutorial anterior, almacenamos cada marcador como una instancia de NSDiccionario, pero esta no es una buena solución para una aplicación basada en documentos. En su lugar, crearemos una clase de marcador personalizado que nos permitirá archivar fácilmente sus datos.

Crear un nuevo NSObject subclase eligiendo Expediente desde el menú, seleccionando Nuevo, y entonces Expediente… . Seleccionar Toque de cacao desde el panel izquierdo y elija Clase objetiva-c De la lista de plantillas de la derecha. Dale a la clase un nombre de Marcador y asegúrese de que es una subclase de NSObject. Especifica dónde quieres guardar la nueva clase y pulsa Crear.



En el archivo de encabezado de nuestro modelo, agregamos las dos propiedades del modelo de marcador que usamos en el tutorial anterior, un nombre y un URL. Ambas propiedades son instancias de NSString. También declaramos un inicializador designado, que toma un nombre y una URL como sus parámetros. Finalmente, es importante asegurar que nuestros Marcador clase se ajusta a la NSCoding protocolo.

 #importar  @interface Bookmark: NSObject  NSString * _name; NSString * _url;  @ propiedad (no atómica, copia) NSString * nombre; @property (nonatomic, copy) NSString * url; - (id) initWithName: (NSString *) nombre yURL: (NSString *) url; @fin

En el archivo de implementación de nuestro modelo, primero definimos dos constantes para el nombre y la URL de nuestro marcador. Esta es una buena práctica, ya que minimizará la posibilidad de que escribamos mal las claves que usaremos en breve. A continuación, implementamos nuestro método de inicialización. Este método es sencillo. Inicializamos nuestra instancia y asignamos el nombre y la URL a nuestras variables de instancia de marcador.

Lo importante es implementar los métodos requeridos para que el Marcador clase conforme a la NSCoding protocolo. Si el NSCoding El protocolo es nuevo para usted, entonces lo invito a leer la Guía de programación de archivos y serializaciones, ya que este es un tema importante para cualquier desarrollador de Cocoa-Touch. Lo esencial de esto es que la NSCoding protocolo nos permite archivar fácilmente y desarchivar instancias de la Marcador clase.

 #import "Bookmark.h" #define kBookmarkName @ "Bookmark Name" #define kBookmarkURL @ "Bookmark URL" @implementation Bookmark @synthesize name = _name, url = _url; #pragma mark - #pragma mark Initialization - (id) initWithName: (NSString *) nombre yURL: (NSString *) url self = [super init]; if (self) self.name = name; self.url = url;  devuélvete a ti mismo;  #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 *) codificador self = [super init]; if (self! = nil) self.name = [coder decodeObjectForKey: kBookmarkName]; self.url = [coder decodeObjectForKey: kBookmarkURL];  devuélvete a ti mismo;  @final

Paso 3: Subclasificar UIDocument

Subclases UIDocumento No es tan difícil como podrías pensar. Como mencioné anteriormente, todo lo que tenemos que hacer es anular dos métodos y crear una propiedad para el modelo de marcador que administrará.

Crea una nueva clase al igual que hicimos para nuestro Marcador clase y dale un nombre de MarcadorDocumento. Asegúrese de que es una subclase de UIDocumento. En el archivo de cabecera de nuestro UIDocumento subclase, añadimos una declaración hacia adelante para el Marcador Clase y creamos una propiedad para nuestro modelo de marcador. No olvides sintetizar los accesores para esta propiedad..

 #importar  @class Bookmark; @interface BookmarkDocument: UIDocument Bookmark * _bookmark;  @property (no atómico, fuerte) Marcador * marcador; @fin

En el archivo de implementación importamos el archivo de cabecera del Marcador Clase y defina otra constante para que sirva como la clave para archivar y desarchivar el modelo de marcador. Como mencioné anteriormente, solo necesitamos anular dos métodos en el UIDocumento subclase, (1) loadFromContents: ofType: error: y 2) contentsForType: error:. El primer método se invocará cuando abrimos un documento, mientras que el segundo método se invocará cuando se guarde un documento. Ambos métodos son llamados por el sistema operativo. Nunca necesitamos llamar a estos métodos directamente..

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

Déjame guiarte a través de loadFromContents: ofType: error:. El primer argumento es contenido de tipo carné de identidad. Esto puede ser una instancia de NSData o NSFileWrapper. Este último solo es aplicable cuando la aplicación utiliza paquetes de archivos. En nuestro caso, podemos esperar un NSData ejemplo. Primero verificamos si la longitud del NSData La instancia no es igual a cero. Inicializamos una instancia de NSKeyedUnarchiver y suministrarlo con el contenido objeto. Al decodificar los datos, obtenemos una instancia de Marcador clase de vuelta Esta es la razón por la cual Marcador clase se ajusta a la NSCoding protocolo. Si la longitud de la NSData la instancia es igual a cero, inicializamos un nuevo marcador con valores predeterminados para nombre y URL. Tenga en cuenta que volvemos al final del método.

 - (BOOL) loadFromContents: (id) contenido deTipo: (NSString *) tipoName error: (NSError * __ autoreleasing *) outError if ([length length]> 0) NSKeyedUnarchiver * unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: contents]; self.bookmark = [unarchiver decodeObjectForKey: kArchiveKey]; [Unarchiver finishDecoding];  else self.bookmark = [[Bookmark alloc] initWithName: @ "Bookmark Name" yURL: @ "www.example.com"];  devolver SÍ; 

los contentsForType: error: El método hace lo contrario. Es decir, suministramos los datos que se deben escribir en el disco. Este objeto de datos es la llamada instantánea de los datos de nuestro modelo. Hacemos esto inicializando una instancia de NSMutableData y usar esto para inicializar una instancia de NSKeyedArchiver. Luego podemos archivar nuestra instancia de marcador para que pueda escribirse en el disco. Este método espera que devolvamos una instancia de NSData Y eso es exactamente lo que hacemos. Nuestro UIDocumento La subclase ya está lista para que la usemos..

 - (id) contentsForType: (NSString *) error de nombre de tipo: (NSError * __ autoreleasing *) outError NSMutableData * data = [[NSMutableData alloc] init]; NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData: data]; [archiver encodeObject: self.bookmark forKey: kArchiveKey]; [archivado finalización de codificación]; datos de retorno; 

Paso 4: Refactoring View Controllers

Hay cuatro elementos de nuestra aplicación que deben ser refactorizados si queremos hacer uso de iCloud Document Storage:
(1) cargar, (2) mostrar, (3) guardar y (4) eliminar marcadores. Vamos a empezar con la carga de marcadores.

Antes de echar un vistazo a la cargar marcadores método, tenemos que declarar una propiedad privada, una instancia de NSMetadataQuery. Quedará claro por qué necesitamos hacer esto en solo unos minutos. No olvide agregar dos declaraciones de importación adicionales a nuestro archivo de implementación del controlador de vista, una para el Marcador clase y uno para el MarcadorDocumento clase.

 #import "ViewController.h" #import "Bookmark.h" #import "BookmarkDocument.h" #import "AddBookmarkViewController.h" @interface ViewController () NSMetadataQuery * _query;  @ propiedad (no atómica, fuerte) NSMetadataQuery * query; @end @implementation ViewController @synthesize bookmarks = _bookmarks; @synthesize tableView = _tableView; @synthesize query = _query;

Paso 4A: Cargando marcadores

En lugar de NSDiccionario instancias, nuestra matriz de marcadores, el origen de datos de nuestra vista de tabla contendrá instancias de MarcadorDocumento clase. Echemos un vistazo al refactorizado. cargar marcadores método. Comenzamos inicializando la matriz de marcadores. A continuación, preguntamos. NSFileManager Para la URL del contenedor de iCloud utilizaremos para almacenar nuestros marcadores. No te dejes llevar por el nombre colorido de este método. URLForUbiquityContainerIdentifier: acepta un argumento, el identificador del contenedor de iCloud al que queremos acceder. Al pasar nil como argumento, NSFileManager seleccionará automáticamente el primer contenedor de iCloud que se declara en el archivo de derechos de nuestra aplicación. Tenga en cuenta que si especifica un identificador de contenedor de iCloud, también debe proporcionar el identificador de equipo. El formato correcto es ..

 - (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 :) nombre: NSMetadataQueryDidFinishGatheringNotification objeto: self.query]; [nc addObserver: auto selector: @selector (queryDidUpdate :) nombre: NSMetadataQueryDidUpdateNotification object: self.query]; [self.query startQuery]; 

Este método no es solo para descubrir dónde podemos almacenar nuestros documentos de iCloud. Al llamar con éxito a este método, el sistema operativo ampliará el espacio de pruebas de nuestra aplicación para incluir el directorio de contenedor de iCloud que especificamos. Esto significa que debemos llamar a este método antes de poder comenzar a leer o escribir datos en este directorio. Si tuviera que registrar la URL devuelta en la consola, notaría dos rarezas, (1) la URL devuelta para el contenedor de iCloud es una URL local (ubicada en el propio dispositivo) y (2) esta URL local no se encuentra en la caja de arena de nuestra aplicación. La forma en que funciona iCloud es que almacenamos los documentos que queremos almacenar en iCloud en este directorio local que NSFileManager nos brinda. El demonio de iCloud, que se ejecuta en nuestro dispositivo en segundo plano, se encargará del aspecto de sincronización de los documentos y lo hará incluso si nuestra aplicación no se está ejecutando..

Debido a que la URL local se encuentra fuera de la zona de pruebas de nuestra aplicación, debemos invocar este método antes de leer o escribir en este directorio. Al invocar este método, le pedimos permiso al sistema operativo para leer y escribir en este directorio.

Sigamos diseccionando la cargar marcadores método. Verificamos que la URL de la que volvemos NSFileManager no es igual a cero. Esto último implica dos cosas importantes: (1) tenemos una ubicación desde la cual podemos leer y escribir y (2) iCloud está habilitado en el dispositivo. El segundo punto es especialmente importante ya que no todos los dispositivos tendrán habilitado iCloud.

Si NSFileManager sí devolvimos una URL válida, inicializamos una instancia de NSMetadataQuery y asignarlo a la variable de instancia que declaramos anteriormente. los NSMetadataQuery clase nos permite buscar documentos en el contenedor de iCloud. Después de inicializar una instancia de NSMetadataQuery, Especificamos el alcance de nuestra búsqueda. En nuestro caso, buscaremos en el Documentos directorio de nuestro contenedor de iCloud ya que es la ubicación donde almacenaremos los documentos de marcadores. Puede refinar la consulta configurando un predicado de búsqueda. Si está familiarizado con Core Data, entonces esto no es nuevo para usted. Nuestra búsqueda será simple, buscaremos todos los documentos en el directorio de documentos de nuestro contenedor de iCloud, de ahí el asterisco en el predicado..

Antes de comenzar nuestra consulta, es importante darse cuenta de que no debemos esperar un resultado inmediato de nuestra consulta. En su lugar, registraremos nuestro controlador de vista como un observador de la NSMetadataQueryDidUpdateNotification y NSMetadataQueryDidFinishGatheringNotification Notificaciones con nuestra instancia de consulta como remitente. Esto significa que se nos notificará cuando nuestra consulta haya devuelto algún resultado o cuando se hayan actualizado los resultados. Finalmente, iniciamos la consulta..

Es importante que mantengamos una referencia a la instancia de consulta para evitar que se libere. Esta es la razón por la que nuestro controlador de vista mantiene una referencia a la consulta (como una variable de instancia) siempre que la consulta se esté ejecutando..

Echemos un vistazo a la queryDidFinish: y queryDidUpdate: Métodos de devolución de llamada de notificación para ver cómo manejar los resultados de la consulta. Ambos métodos pasan el objeto remitente de la notificación, el NSMetadataQuery ejemplo, a un método de conveniencia, processQueryResults:. Cuando echamos un vistazo a este método, vemos que primero comenzamos por deshabilitar las actualizaciones para la consulta. Esto es importante ya que los resultados de la consulta pueden recibir actualizaciones en tiempo real cuando se producen cambios y debemos evitarlo mientras estemos procesando los resultados de la consulta. A continuación, eliminamos todos los objetos de nuestra matriz de marcadores y enumeramos los resultados de la consulta. Cada elemento de la matriz de resultados es una instancia de NSMetadataItem, que contiene los metadatos asociados con cada documento favorito, incluida la URL del archivo que necesitamos para abrir el documento. Solicitamos a cada elemento de metadatos la URL del archivo e inicializamos el documento respectivo.

Tenga en cuenta que inicializar un documento favorito no significa que lo hayamos cargado desde el disco. Recuerde que esto se hace enviando a nuestro documento favorito un mensaje de openWithCompletionHandler:. Si la operación de apertura es exitosa y el documento está cargado, lo agregamos a nuestra matriz de marcadores y lo mostramos en la vista de tabla. Finalmente, debemos eliminar nuestro controlador de vista como observador, ya que ya no necesitamos recibir notificaciones en este momento..

 - (void) queryDidFinish: (NSNotification *) notificación NSMetadataQuery * query = [objeto de notificación]; // Detener actualizaciones [consulta disableUpdates]; // Stop Query [query stopQuery]; // Borrar marcadores [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: ^ (éxito BOOL) if (success) [self.bookmarks addObject: document]; [self.tableView reloadData]; ]; ]; [[NSNotificationCenter defaultCenter] removeObserver: self]; 

Paso 4B: Visualización de marcadores en la vista de tabla

El código para mostrar los marcadores en nuestra vista de tabla no necesita cambiar mucho. En lugar de buscar el correcto NSDiccionario instancia de la fuente de datos, obtenemos una instancia de la MarcadorDocumento clase. El acceso al nombre y la URL del marcador también debe actualizarse.

 - (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];  // Fetch Bookmark BookmarkDocument * document = [self.bookmarks objectAtIndex: indexPath.row]; // Configurar celda cell.textLabel.text = document.bookmark.name; cell.detailTextLabel.text = document.bookmark.url; celda de retorno 

Paso 4C: Guardar un marcador

Dirígete a la salvar: método en Añadir BookmarkViewController. En lugar de crear un NSDiccionario y enviándolo a nuestro controlador de vista principal, creamos un nuevo Marcador ejemplo. Eso es. El resto se maneja en la saveBookmark: Método de nuestro controlador de vista principal. No olvide agregar una declaración de importación para el Marcador clase.

 - (IBAction) guardar: (id) remitente Bookmark * bookmark = [[Bookmark alloc] initWithName: self.nameField.text yURL: self.urlField.text]; [self.viewController saveBookmark: marcador]; [self dismissViewControllerAnimated: YES complete: nil]; 

Guardar un marcador en nuestro contenedor de iCloud es casi tan simple como guardarlo en la caja de arena de nuestra aplicación. Primero, preguntamos NSFileManager para la URL de nuestro contenedor iCloud como hicimos anteriormente. Sobre la base de esa URL, construimos la URL correcta para guardar el documento de marcador en el Documentos Directorio del contenedor iCloud. El nombre de nuestro documento puede ser lo que queramos, siempre y cuando su nombre sea único. He elegido usar el nombre del marcador y una marca de tiempo. El usuario no verá este nombre de archivo, por lo que el nombre no es tan importante. Lo importante es que es único..

Tenemos una instancia de marcador, pero aún no tenemos un documento de marcador. Creamos un nuevo documento favorito al inicializarlo con la URL que acabamos de crear. A continuación, asignamos nuestro nuevo marcador a la propiedad de marcador del documento. Finalmente, agregamos el documento a la matriz de marcadores y volvemos a cargar la vista de tabla..

Guardar el documento en el contenedor de iCloud es fácil. Iniciamos la operación de guardar de la que hablé anteriormente enviando a nuestro nuevo documento el mensaje saveToURL: forSaveOperation: completedHandler:. El segundo parámetro de este método especifica el tipo de operación de guardado. En nuestro caso, pasamos. UIDocumentSaveForCreating, lo que significa crear un nuevo documento favorito. Como no tenemos que hacer nada especial en nuestro ejemplo, simplemente registramos un mensaje en la consola cuando finaliza la operación de guardar.

Es posible que hayas notado que nuestra declaración de método ha cambiado ligeramente. Ya no pasamos una instancia de NSDiccionario como el único argumento. En cambio pasamos una instancia de la Marcador clase. Asegúrese de actualizar el archivo de encabezado para reflejar este cambio. También deberá agregar una declaración de clase foward para evitar que aparezcan advertencias del compilador. Estas son tareas con las que ya deberías estar familiarizado.

 - (no válido) saveBookmark: (Bookmark *) bookmark // Save Bookmark NSURL * baseURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil]; if (baseURL) NSURL * documentsURL = [baseURL URLByAppendingPathComponent: @ "Documentos"]; NSURL * documentURL = [documentsURL URLByAppendingPathComponent: [NSString stringWithFormat: @ "Bookmark _% @ -% f", bookmark.name, [[NSDate date] timeIntervalSince1970]]]; BookmarkDocument * document = [[BookmarkDocument alloc] initWithFileURL: documentURL]; document.bookmark = marcador; // Agregar marcador a marcadores [self.bookmarks addObject: document]; // Reload Table View [self.tableView reloadData]; [document saveToURL: documentURL forSaveOperation: UIDocumentSaveForCreating completedHandler: ^ (éxito de BOOL) if (success) NSLog (@ "Save successed.");  else NSLog (@ "Error al guardar"); ]; 

Paso 4D: Eliminar marcadores

La última pieza faltante del rompecabezas es la eliminación de marcadores. Esto es muy fácil comparado con lo que hemos hecho hasta ahora. Obtenemos el documento de marcador correcto de la fuente de datos y le informamos NSFileManager para eliminarlo del contenedor de iCloud pasando la URL correcta. Esto también eliminará el documento en iCloud. Eso es lo fácil que es. Por supuesto, también actualizamos la fuente de datos y la vista de tabla..

 - (void) tableView: (UITableView *) aTableView commitEditingStyle: (UITableViewCellEditingStyle) estilo de edición paraRowAtIndexPath. ; // Eliminar documento NSError * error = nil; if (! [[NSFileManager defaultManager] removeItemAtURL: document.fileURL error: & error]) NSLog (@ "Se produjo un error al intentar eliminar el documento. Error% @ con la información del usuario% @.", error, error.userInfo);  // Actualizar marcadores [self.bookmarks removeObjectAtIndex: indexPath.row]; // Actualizar vista de tabla [aTableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: indexPath] withRowAnimation: UITableViewRowAnimationFade]; 

Conclusión

En este tutorial, hemos reformulado nuestra aplicación para usar el almacenamiento de documentos de iCloud en lugar del almacenamiento de valor clave de iCloud. A pesar de que hemos revisado bastante código, el proceso fue bastante sencillo. Ahora tenemos una aplicación basada en documentos que es mucho más adecuada para manejar grandes cantidades de datos de usuarios. Los componentes básicos están en su lugar y extender la aplicación requiere poco esfuerzo por nuestra parte. Tenga en cuenta que nuestra aplicación sigue siendo una implementación mínima de un administrador de marcadores. Por ejemplo, no hay opción para editar marcadores. También deberíamos realizar más comprobaciones de errores si queremos convertir nuestra aplicación en una aplicación robusta y confiable que esté lista para el lanzamiento..

También te habrás dado cuenta de que tenemos varios métodos que ya no necesitamos. He eliminado estos métodos del ejemplo de código final y le sugiero que haga lo mismo. La eliminación de código obsoleto también es parte del proceso de refactorización y es esencial cuando desea mantener