ICloud y UIDocument: Más allá de lo básico y coma; Parte 2 & sol; 4

September 15|0 Vistas|

Resumen: ¡Aprende a hacer una aplicación completa de UIDocument + iCloud! Esta es una entrada del blog del administrador del sitio, Ray Wenderlich, desarrollador de software independiente y jugador. ¡Bienvenido de nuevo a nuestra serie de tutoriales de aplica

Advertisement

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4


¡Aprende a hacer una aplicación completa de UIDocument + iCloud!

Esta es una entrada del blog del administrador del sitio, Ray Wenderlich, desarrollador de software independiente y jugador.

¡Bienvenido de nuevo a nuestra serie de tutoriales de aplicaciones iCloud basadas en documentos!

En esta serie de tutoriales, estamos haciendo una aplicación completa basada en documentos iCloud llamada PhotoKeeper, con características que van más allá de lo básico.

En la primera parte de la serie, creamos clases de modelo para nuestra aplicación y un contenedor de UIDocument. También agregamos lógica a la lista y agregamos archivos locales.

En esta segunda parte de la serie, vamos a hacer la aplicación totalmente funcional cuando se trata de archivos locales. Mejoraremos la apariencia de nuestra vista maestra, implementaremos la vista de detalle y agregaremos soporte para cambiar el nombre y eliminar archivos.

Si estás ansioso por entrar en iCloud, no te preocupes: conseguir un soporte de UIDocument, como lo estamos haciendo aquí, es un requisito previo. Estamos estableciendo un marco que facilitará el cambio a iCloud.

Este proyecto continúa donde lo dejamos la última vez, así que si no lo tienes ya agarra el ejemplo de código anterior y abre el proyecto. ¡Vamos a empezar!

Una mejor vista de tabla

En este momento nuestra vista de tabla es el aburrido estilo predeterminado que la plantilla hizo para nosotros. Vamos a arreglar esto para que sea más la forma que queremos para PhotoKeeper.

Abra MainStoryboard.storyboard y seleccione la vista de tabla dentro del controlador de vista maestra. Cambie al Inspector de tamaño y establezca la altura de fila en 80:

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4


A continuación, seleccione la celda de vista de tabla y establezca el estilo en personalizado para quitar los controles predeterminados:

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4


Arrastre un UIImageView, UITextField y UILabel en la celda por lo que parece más o menos como el siguiente:

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4

Tenga en cuenta que estamos agregando un UITextField en lugar de un UILabel para el nombre del documento para que más tarde podemos implementar el cambio de nombre del documento.

Hablando del UITextField - selecciónelo e ir al inspector de los atributos. Establezca el estilo de borde en Ninguno, el botón Borrar para aparecer durante la edición, la fuente en el sistema 17.0, la capitalización en palabras y la corrección en No:

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4


Para admitir bien la orientación horizontal, establezca los atributos de autosizing del campo de texto y etiquete de la siguiente manera:

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4


Para completar nuestros controles, necesitamos una forma de acceder a ellos a través del código. Podríamos conseguirlas desde la celda por etiqueta, pero para mantener nuestro código más limpio y más fácil de leer, haremos una subetapa UITableView personalizada.

Cree un nuevo archivo con la plantilla de clase iOS \ Cocoa Touch \ Objective-C, póngale PTKEntryCell y convierta en una subclase de UITableViewCell. A continuación, reemplace el contenido de PTKEntryCell.h con lo siguiente:

  #import <UIKit / UIKit.h> @interface PTKEntryCell: UITableViewCell @property (débil, no atómico) IBOutlet UIImageView * photoImageView;  @property (débil, no atómico) IBOutlet UITextField * titleTextField;  @property (débil, no atómico) IBOutlet UILabel * subtitleLabel;  @fin 

Aquí hacemos puntos de venta para los controles en nuestra celda, y también agregamos un delegado que podemos notificar cuando el usuario edite el texto.

Mientras estás en él, cambia a PTKEntryCell.m y reemplaza el contenido por lo siguiente:

  #import "PTKEntryCell.h" @implementación PTKEntryCell @synthesize photoImageView;  @synthesize titleTextField;  @synthesize subtitleLabel;  - (void) setEditing: (BOOL) edición animada: (BOOL) animado {[super setEditing: edición animado: animado];  [UIView animateWithDuration: 0.1 animaciones: ^ {if (edición) {titleTextField.enabled = YES;  TitleTextField.borderStyle = UITextBorderStyleRoundedRect;  } Else {titleTextField.enabled = NO;  TitleTextField.borderStyle = UITextBorderStyleNone;  }}];  }   @fin 

Aquí implementamos setEditing para cambiar nuestro campo de texto en modo de edición o no basado en si la celda está en el modo de edición.

Ahora vamos a configurar nuestra vista de tabla para usar esta clase de celda personalizada en el editor de Storyboard. Abra MainStoryboard.storyboard, seleccione la celda y, en el inspector de identidad, establezca PTKEntryCell:

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4


Ahora arrastre desde la celda hasta la vista de imagen, el campo de texto y los controles de etiqueta, conectándolos a las salidas photoImageView, titleTextField y subtitleLabel.

Vamos a configurar el controlador de vista maestra para usar esta celda ahora. Abra PTKMasterViewController.h y marque la clase como implementar UITextFieldDelegate:

  #import <UIKit / UIKit.h> @interface PTKMasterViewController: UITableViewController <UITextFieldDelegate> @end 

A continuación, cambie a PTKMasterViewController.m e importe PTKEntryCell.h en la parte superior del archivo:

  #import "PTKEntryCell.h" 

Y reemplazar tableView: cellForRowAtIndexPath: con lo siguiente:

  - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath {PTKEntryCell * cell = [tableView dequeueReusableCellWithIdentifier: @ "Cell"];  PTKEntry * entrada = [objetos _objetosAtIndex: indexPath.row];  Cell.titleTextField.text = entry.description;  Cell.titleTextField.delegate = self;  If (entry.metadata && entry.metadata.thumbnail) {cell.photoImageView.image = entry.metadata.thumbnail;  } Else {cell.photoImageView.image = nil;  } If (entrada.versión) {cell.subtitleLabel.text = [entry.version.modificationDate mediumString];  } Else {cell.subtitleLabel.text = @ "";  } Return cell;  } 

Esto es similar a lo que teníamos antes, excepto que estamos estableciendo los controles en nuestro nuevo PTKEntryCell. Implementaremos la devolución de llamadas del delegado más tarde, así que no te preocupes por ello por ahora.

Eso es - compilar y ejecutar, y ahora la aplicación se ve un poco mejor!

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4

No muestra fotos todavía (ya que no teníamos forma de establecer fotos), pero eso es lo que haremos a continuación:]

Creación de la vista de detalle

En este momento nuestra vista de detalle no funciona - es sólo la vista por defecto por defecto creada para nosotros por la plantilla. Vamos a arreglar eso.

Abra MainStoryboard.storyboard y busque el controlador de vista de detalle. Elimine la etiqueta que se encuentra en el medio y añada un UIImageView viejo y grande llenando toda la vista:

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4

Abra el Editor Asistente, asegúrese de que PTKDetailViewController.h esté visible en el editor asistente y arrastre el control desde la vista de imagen debajo de la interfaz @. Escriba imageView para el nombre y haga clic en Conectar.

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4


A continuación, cambie a PTKDetailViewController.h y modifique el archivo para que se vea como lo siguiente:

  #import <UIKit / UIKit.h> @class PTKDocument;  @class PTKDetailViewController;  @protocol PTKDetailViewControllerDelegate - (void) detailViewControllerDidClose: (PTKDetailViewController *) detailViewController;  @end @interface PTKDetailViewController: UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate> @property (fuerte, no atómico) PTKDocument * doc;  @property (débil, no atómico) IBOutlet UIImageView * imageView;  @property (weak) id <PTKDetailViewControllerDelegate> delegate;  @fin 

Aquí hemos añadido un protocolo / delegado que podemos notificar cuando el usuario ha terminado, añadimos una propiedad del PTKDocument (abierto) que debemos mostrar y marcamos nuestra clase como implementando dos protocolos que necesitaremos para usar un selector de imágenes.

Tenga en cuenta que estamos pasando un PTKDocument abierto como el elemento a mostrar (en lugar de la fileURL). Esta fue una decisión de diseño. Puede tomar tiempo abrir un documento, especialmente si es grande o no totalmente sincronizado con iCloud, y depende de dónde desea pasar ese tiempo - antes de la transición a la vista de detalle o después. Elegimos antes para esto.

A continuación, cambie a PTKDetailViewController.m y reemplácelo por lo siguiente. Nota Estoy dando un montón de código a la vez aquí, pero esto es bastante simple, así que debería estar bien.

  #import "PTKDetailViewController.h" #import "PTKDocument.h" #import "PTKData.h" #import "UIImageExtras.h" @interface PTKDetailViewController () - (void) configureView;  @end @implementation PTKDetailViewController {UIImagePickerController * _picker;  } @synthesize doc = _doc;  @synthesize imageView = _imageView;  @synthesize delegate = _delegate;  #pragma mark - Administrar el elemento de detalle - (void) setDoc: (id) newDoc {if (_doc! = NewDoc) {_doc = newDoc;  // Actualizar la vista.  [Autoconfiguración];  }} - (void) configureView {// Actualiza la interfaz de usuario para el elemento de detalle.  Self.title = [descripción de self.doc];  If (self.doc.photo) {self.imageView.image = self.doc.photo;  } Else {self.imageView.image = [UIImage imageNamed: @ "defaultImage.png"];  }} - (void) viewDidLoad {[super viewDidLoad];  // Hacer cualquier configuración adicional después de cargar la vista, normalmente desde un plumín.  UIBarButtonItem * backButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemDone objetivo: acción propia: @selector (doneTapped :)];  Self.navigationItem.leftBarButtonItem = backButtonItem;  [Self.navigationItem setHidesBackButton: SI animado: SI];  UITapGestureRecognizer * tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: acción propia: @selector (imageTapped :)];  [Self.view addGestureRecognizer: tapRecognizer];  [Autoconfiguración];  } - (void) viewDidUnload {[self setImageView: nil];  [Super viewDidUnload];  } - (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation {return (interfaceOrientation! = UIInterfaceOrientationPortraitUpsideDown);  } #pragma mark Reclamaciones - (void) imageTapped: (UITapGestureRecognizer *) reconocedor {if (! _picker) {_picker = [[UIImagePickerController alloc] init];  _picker.delegate = self;  _picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;  _picker.allowsEditing = NO;  } [Auto presentModalViewController: _picker animado: YES];  } - (void) doneTapped: (id) sender {NSLog (@ "Cierre% @ ...", self.doc.fileURL);  [Self.doc saveToURL: self.doc.fileURL forSaveOperation: UIDocumentSaveForOverwriting completionHandler: ^ (éxito BOOL) {[self.doc closeWithCompletionHandler: ^ (éxito BOOL) {dispatch_async (dispatch_get_main_queue (), ^ {if (! Success) {NSLog @ "No se pudo cerrar% @", self.doc.fileURL); // De todas maneras ...} [self.delegate detailViewControllerDidClose: self];});  }];  }];  } #pragma mark UIImagePickeerControllerDelegate - (void) imagePickerControllerDidCancel: (UIImagePickerController *) selector {[self dismissViewControllerAnimated: SI finalización: nil];  } - (void) imagePickerController: (UIImagePickerController *) selector didFinishPickingMediaWithInfo: (NSDictionary *) info {UIImage * image = (UIImage *) [objeto de informaciónObjeto: UIImagePickerControllerOriginalImage];  CGSize mainSize = self.imageView.bounds.size;  UIImage * sImage = [image imageByBestFitForSize: mainSize];  // [image scaleToFitSize: mainSize];  Self.doc.photo = sImage;  Self.imageView.image = sImage;  [Self dismissViewControllerAnimated: SI finalización: nil];  }   @fin 

Lea esto y asegúrese de entender lo que está pasando. Hay sólo algunas cosas que señalar aquí:

  • Cuando el usuario cambia la imagen, la cambiamos inmediatamente en el documento a través del setter que escribimos anteriormente. Dado que el instalador utiliza el administrador de deshacer, UIDocument sabe sobre el cambio por lo que auto-guardar el documento en algún momento en el futuro.
  • Cuando se pulsa el botón finalizado, cerramos el documento. Esto desencadena una grabación si no se ha guardado automáticamente. Le notificamos al delegado cuando hayamos terminado para que nos despidan.

Casi hecho - sólo tiene que hacer que el controlador de vista maestro utilizar esto. En primer lugar, ahora la plantilla se ha hecho es así cuando una fila es tapping un segue se realiza automáticamente (bypassing tableView: didSelectRowAtIndexPath). Primero debemos modificar esto para que tableView: didSelectRowAtIndexPath se llame primero, así que tenemos la oportunidad de abrir el documento antes de realizar el segue.

Para corregir esto, abra MainStoryboard.storyboard y elimine el avance entre el controlador de vista maestro y el controlador de vista de detalle. Luego, arrastre desde el controlador de vista maestro (NO la celda de vista de tabla) hasta el controlador de vista de detalle y elija Empujar desde la ventana emergente de seguimiento. A continuación, seleccione el segue y el nombre que showDetail:

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4


A continuación, abra PTKMasterViewController.h y marque la clase como implementando el delegado del controlador de vista de detalle:

  #import <UIKit / UIKit.h> #import "PTKEntryCell.h" #import "PTKDetailViewController.h" @interface PTKMasterViewController: UITableViewController <UITextFieldDelegate, PTKDetailViewControllerDelegate> @end 

A continuación, cambie a PTKMasterViewController.m y realice los cambios siguientes:

  // 1) Agregue justo encima de la sección "Ver ciclo de vida" con awakeFromNib #pragma mark PTKDetailViewControllerDelegate - (void) detailViewControllerDidClose: (PTKDetailViewController *) detailViewController {[auto.navigationController popViewControllerAnimated: YES];  NSFileVersion * version = [NSFileVersion currentVersionOfItemAtURL: detailViewController.doc.fileURL];  [Self addOrUpdateEntryWithURL: detailViewController.doc.fileURL metadatos: detailViewController.doc.metadata state: detailViewController.doc.documentState version: version];  } // 2) Agregue a la derecha encima de prepareForSegue - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath {PTKEntry * entry = [_objects objectAtIndex: indexPath.row];  [Self.tableView deselectRowAtIndexPath: indexPath animado: SI];  _selDocument = [[PTKDocument alloc] initWithFileURL: entry.fileURL];  [_selDocument openWithCompletionHandler: ^ (éxito de BOOL) {dispatch_async (dispatch_get_main_queue (), ^ {[self performSegueWithIdentifier: @ "showDetail" remitente: self];});  }];  } // 3) Reemplace prepareForSegue con lo siguiente: - (void) prepareForSegue: (UIStoryboardSegue *) sigue remitente: (id) sender {if ([[segue identificador] isEqualToString: @ "showDetail" :yo];  [[Segue destinationViewController] setDoc: _selDocument];  }} 

Vamos a pasar por estos métodos uno por uno:

  1. Cuando se completa la vista de detalle, saltamos el controlador de vista y actualizamos nuestra entrada de vista de tabla.
  2. Cuando se selecciona una fila, abrimos el documento y realizamos el segue una vez que se ha cargado.
  3. Cuando se realiza un seguimiento, pasamos el documento que se va a editar a la vista de detalle y también nos fijamos como su delegado.

Si todavía está oxidado con el concepto de segues, puede que desee ver nuestro tutorial de guión gráfico.

¡Eso es! Compilar y ejecutar, y ahora puede configurar fotos en sus documentos y se mantendrá incluso si se apaga / reiniciar la aplicación!

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4

Eliminación de documentos

Hola, estamos muy cerca de una aplicación funcional aquí! Pero ahora mismo, aunque podemos crear archivos, no podemos eliminar las moscas. Vamos a añadir que rápido real.

Realice los cambios siguientes en PTKMasterViewController.m:

  // Añadir al final de la sección "Métodos de gestión de entrada" - (void) removeEntryWithURL: (NSURL *) fileURL {int index = [auto indexOfEntryWithFileURL: fileURL];  [_objects removeObjectAtIndex: index];  [Self.tableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: [NSIndexPath indexPathForRow: index inSection: 0]] conRowAnimation: UITableViewRowAnimationLeft];  } // Añadir al final de la sección "Métodos de gestión de archivos" - (void) deleteEntry: (PTKEntry *) entrada {// Simple delete para iniciar NSFileManager * fileManager = [[NSFileManager alloc] init];  [FileManager removeItemAtURL: error entry.fileURL: nil];  // Vista de corrección [self removeEntryWithURL: entry.fileURL];  } // Replace tableView: commitEditingStyle: forRowAtIndexPath - (void) tableView: (UITableView *) tableView commitEditingStyle: (UITableViewCellEditingStyle) editingStyle forRowAtIndexPath: (NSIndexPath *) indexPath {if (editingStyle = UITableViewCellEditingStyleDelete) {PTKEntry * entry = [_objects objectAtIndex: IndexPath.row];  [Self deleteEntry: entrada];  }} 

La única parte que vale la pena mencionar aquí es que la eliminación se realiza por el método removeItemAtURL de NSFileManager. Esto causará problemas con iCloud tal cual, pero funcionará bien para los documentos locales, por lo que lo mantendremos de esta manera por ahora.

¡Compila y corre, y ahora puedes deslizar filas para eliminarlos permanentemente! Asegúrese de apagar y reiniciar la aplicación para verificar que se han ido para siempre.

Cambiar el nombre de los documentos

A continuación, debemos agregar una forma para que los usuarios renombren sus archivos en lugar de tener siempre "Foto", "Foto 1", etc.

Primero vamos a agregar un método para cambiar el nombre de una entrada a un nombre de archivo dado. Añada este método a PTKMasterViewController.m a la sección "Métodos de gestión de entrada", justo debajo de addOrUpdateEntryWithURL: metadata: state: version:

  - (BOOL) renameEntry: (PTKEntry *) entrada a: (NSString *) nombreDeArchivo {// Bail si no renombre realmente si ([entry.description isEqualToString: filename]) {return YES;  } // Compruebe si se puede cambiar el nombre del archivo NSString * newDocFilename = [NSString stringWithFormat: @ "% @.% @", Nombre de archivo, PTK_EXTENSION];  If ([auto docNameExistsInObjects: newDocFilename]) {NSString * message = [NSString stringWithFormat: @ "\"% @ \ "ya se ha tomado. Elija un nombre diferente.", Nombre de archivo];  UIAlertView * alertView = [[UIAlertView alloc] initWithTitle: nil mensaje: mensaje delegate: nil cancelButtonTitle: nil otherButtonTitles: @ "OK", nil];  [AlertView mostrar];  Devolver NO;  } NSURL * newDocURL = [auto getDocURL: newDocFilename];  NSLog (@ "Mover% @ a% @", entry.fileURL, newDocURL);  // Simple cambio de nombre para iniciar NSFileManager * fileManager = [[NSFileManager alloc] init];  NSError * error;  BOOL success = [fileManager moveItemAtURL: entry.fileURL toURL: error de nuevoDocURL: & error];  If (! Success) {NSLog (@ "No se pudo mover el archivo:% @", error.localizedDescription);  Devolver NO;  } // Arregla la entrada entry.fileURL = newDocURL;  Int index = [auto indexOfEntryWithFileURL: entry.fileURL];  [Self.tableView reloadRowsAtIndexPaths: [NSArray arrayWithObject: [NSIndexPath indexPathForRow: index inSection: 0]] conRowAnimation: UITableViewRowAnimationNone];  Devolver SI;  } 

Esto comprueba si el nombre está disponible (y advierte al usuario si no), y de otra manera mueve el archivo usando la API moveItemAtURL de NSFileManager. Esta API en particular tiene problemas cuando se trata de iCloud (que discutiremos más adelante), pero funciona muy bien con los archivos locales por lo que lo mantendremos de esa manera.

Ahora vamos a llamar a este método cuando el usuario cambia el nombre de un archivo por modificar el campo de texto de una celda mientras está en modo de edición. ¿Recuerdas cómo agregamos un delegado a UITableViewCell para notificarnos cuando el usuario cambia el texto del nombre de archivo, pero nunca lo implementaste? ¡Ahora es el momento!

Agregue el siguiente código justo encima de la sección "Ver ciclo de vida" con awakeFromNib:

  #pragma mark Vistas de texto - (void) textChanged: (UITextField *) textField {UIView * view = textField.superview;  Mientras que (! [View isKindOfClass: [PTKEntryCell class]]) {view = view.superview;  } PTKEntryCell * cell = (PTKEntryCell *) ver;  NSIndexPath * indexPath = [self.tableView indexPathForCell: cell];  PTKEntry * entrada = [objetos _objetosAtIndex: indexPath.row];  NSLog (@ "Quiere cambiar el nombre de% @ a% @", entry.description, textField.text);  [Self renameEntry: entrada a: textField.text];  } - (BOOL) textFieldShouldReturn: (UITextField *) textField {[textField resignFirstResponder];  [Self textChanged: textField];  Devolver SI;  } 

Bastante simple, ¿eh? ¡Compila y corre, y ahora puedes renombrar archivos!

Bonus: Corrección de desplazamiento

Si tiene muchas fotos, puede notar que si pulsa en un campo de texto hacia la parte inferior de la vista de tabla, el keybaord se superpone para que no pueda ver lo que está editando. Eso es molesto, ¿eh?

Aquí hay una solución rápida cortesía de ZeLogolas en StackOverflow. Realice los cambios siguientes en PTKMasterViewController.m:

  // Añadir variable de instancia privada UITextField * _activeTextField;  // Añadir dentro de la sección "Vistas de texto", arriba textChanged - (void) keyboardWillShow: (NSNotification *) note {// Obtenga el tamaño del teclado CGRect keyboardBounds;  [[Note.userInfo valueForKey: UIKeyboardFrameBeginUserInfoKey] getValue: & keyboardBounds];  // Detectar orientación UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];  CGRect frame = self.tableView.frame;  // Iniciar animación [UIView beginAnimations: nil context: NULL];  [UIView setAnimationBeginsFromCurrentState: YES];  [UIView setAnimationDuration: 0.3f];  // Reduce el tamaño de la vista Tabla si (orientación == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) frame.size.height - = keyboardBounds.size.height;  Else frame.size.height - = keyboardBounds.size.width;  // Aplique el nuevo tamaño de la vista de tabla self.tableView.frame = frame;  // Desplaza la vista de tabla para ver el TextField justo encima del teclado si (_activeTextField) {CGRect textFieldRect = [auto.tableView convertRect: _activeTextField.superview.bounds fromView: _activeTextField.superview];  [Self.tableView scrollRectToVisible: textFieldRect animated: NO];  } [UIView commitAnimations];  } - (void) keyboardWillHide: (NSNotification *) note {// Obtenga el tamaño del teclado CGRect keyboardBounds;  [[Note.userInfo valueForKey: UIKeyboardFrameBeginUserInfoKey] getValue: & keyboardBounds];  // Detectar orientación UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];  CGRect frame = self.tableView.frame;  [UIView beginAnimations: nil context: NULL];  [UIView setAnimationBeginsFromCurrentState: YES];  [UIView setAnimationDuration: 0.3f];  // Reduce el tamaño de la vista Tabla si (orientación == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) frame.size.height + = keyboardBounds.size.height;  Else frame.size.height + = keyboardBounds.size.width;  // Aplique el nuevo tamaño de la vista de tabla self.tableView.frame = frame;  [UIView commitAnimations];  } - (IBAction) textFieldDidBeginEditing: (UITextField *) textField {_activeTextField = textField;  } - (IBAction) textFieldDidEndEditing: (UITextField *) textField {_activeTextField = nil;  } // Añadir en la parte inferior de viewDidLoad [[NSNotificationCenter defaultCenter] addObserver: auto selector: @selector (keyboardWillShow :) nombre: UIKeyboardWillShowNotification objeto: nil];  [[NSNotificationCenter defaultCenter] addObserver: auto selector: @selector (keyboardWillHide :) nombre: UIKeyboardWillHideNotification objeto: nil];  // Añadir en la parte inferior de viewDidUnload [[NSNotificationCenter defaultCenter] removeObserver: self]; 

Compilar y ejecutar, y ahora se desplazará automáticamente si selecciona un elemento en la parte inferior!

¿A dónde ir desde aquí?

Aquí hay una descarga con el estado de la muestra de código hasta ahora.

En este punto, tiene una aplicación totalmente funcional basada en UIDocument que almacena documentos localmente. ¡Ya ha establecido las bases que harán que la adición del soporte iCloud sea mucho más fácil!

En la siguiente parte de la serie, ¡finalmente llegaremos a iCloud! Conseguiremos los fundamentos funcionando, y luego en la parte final de la serie, cubriremos aspectos más avanzados como mover archivos desde / hacia iCloud, manejar conflictos y mucho más.

Si tiene preguntas, comentarios o sugerencias sobre mejores maneras de hacer las cosas, por favor únase a la discusión del foro a continuación. :]

ICloud y UIDocument: Más allá de lo básico y coma;  Parte 2 & sol; 4

Esta es una entrada del blog del administrador del sitio, Ray Wenderlich, desarrollador de software independiente y jugador.

Etiqueta:

Artículos relacionados

Popular

Último