Ejercicios

Ejercicio 1: Property lists y serialización (5 puntos)

Vamos a realizar una pequeña aplicación en la que los datos se guarden/recuperen de un archivo .plist. Desde el punto de vista del usuario consistirá en una única "pantalla" con un Text View para editar un mensaje y un Label que mostrará la fecha y hora de edición. Los datos deben conservarse aunque salgamos de la aplicación.

Llama al proyecto PersistenciaBasica.

Interfaz gráfico (0,5 puntos)

Crea la interfaz:

  • Inserta el Text View y el Label en el storyboard

  • En el ViewController

    • Crea dos outlet para acceder al contenido de ambos componentes. Recuerda que tienes que hacer Ctrl+arrastrar.

      • Crea una propiedad opcional llamada fechaEdicion de tipo Date, que representará la fecha y hora en que se haya editado el texto.

Queremos que cuando haga tap en cualquier parte de la pantalla se acabe la edición del Text View. Para ello podemos añadir el siguiente método al ViewController:

override func touchesEnded(_ touches: Set<UITouch>, with: UIEvent?) {
    //CUIDADO: estamos suponiendo que el outlet del text view se llama "mensaje"
    //cámbialo por como lo hayas llamado tú
    self.mensaje.resignFirstResponder()
}

Finalmente, queremos detectar cuándo se ha editado el texto del Text View. Para ello tenemos que hacer que el view controller implemente el protocolo UITextViewDelegate. En la cabecera del ViewController añadimos el protocolo:

class ViewController : UIViewController, UITextViewDelegate {
    ...

Ahora en el mismo ViewController indicamos que este objeto es el delegate del Text View. En el método viewDidLoad añadimos

//Cambia "mensaje" por como se llame el outlet del text view
self.mensaje.delegate = self;

Y finalmente también en el ViewController podemos detectar cuándo se ha hecho la edición implementando este método:

func textViewDidEndEditing(_ textView: UITextView) {
    self.fechaEdicion = Date()
    //SUPONEMOS que el outlet del label se llama "fechaLabel"
    //CAMBIALO si es necesario
    self.fechaLabel.text = DateFormatter.localizedString(
               from:self.fechaEdicion!, 
               dateStyle: .short, timeStyle: .medium)
}

Comprobar que lo anterior funciona correctamente, que al editar el texto y pulsar sobre la pantalla se dispara el método anterior, y en el label se muestra la fecha y hora de edición.

Detectar que salimos de la aplicación (0,5 puntos)

Lo primero es detectar cuándo salimos de la aplicación para poder hacer el guardado de los datos en ese momento. Para ello podemos suscribirnos a una notificación del sistema llamada UIApplication.didEnterBackgroundNotification.

Introducir el siguiente código en el método viewDidLoad del view controller:

let nc = NotificationCenter.default
nc.addObserver(self, selector:#selector(self.vamosABackground),
            name: UIApplication.didEnterBackgroundNotification,
            object: nil)

El código anterior llama al método vamosABackground cuando se recibe la notificación. Para probarlo, podéis hacer una implementación “provisional” del método:

@objc func vamosABackground() {
    print("Nos notifican que vamos a background");
}

Ahora, para probar que esto funciona, hay que arrancar la aplicación y salir de ella como lo haríamos en un dispositivo real, es decir, pulsando sobre el botón Home. También podemos hacerlo en el menú del simulador Hardware > Home, o bien con el atajo de teclado Cmd+Shift+H. Al hacer esto debe aparecer el mensaje en el log. Comprueba que es así.

Almacenar los datos en el .plist (2 puntos)

Queremos guardar el texto del mensaje y la fecha de edición (esta última como una fecha, no como un texto). Podemos almacenar ambos valores usando un struct. Crea un nuevo tipo struct llamado DatosMensaje con los campos necesarios, puedes guardarlo por ejemplo en un archivo DatosMensaje.swift. Recuerda que para que sea serializable debe declararse como conforme al protocolo Codable.

En el método vamosABackground que hemos creado antes tenemos que hacer esto (puedes tomar como base el código de la transparencia número 23):

  • Obtener la URL del directorio Documents de la aplicación

  • Crear a partir de ella la URL del fichero mensaje.plist donde se guardarán los datos

  • Instanciar un struct con el texto del mensaje y la fecha de edición

  • Guardar el archivo .plist con un PropertyListEncoder

Comprobar que cuando se sale de la aplicación pulsando el botón Home se ha creado el archivo mensaje.plist con el contenido adecuado. Usad la aplicación SimSim para ver la carpeta del Mac donde se guarda el sandbox de vuestra app.

Recuperar los datos del .plist (2 puntos)

Si salimos de la aplicación pulsando el botón Home y volviendo a entrar en ella veremos muy probablemente que se conservan los datos, pero es porque el sistema no ha liberado la memoria. Para recuperarlos al arrancar la aplicación “desde cero”, tenemos que añadir código al viewDidLoad del view controller: (los dos primeros pasos son los mismos que para guardar los datos)

  • Obtener la URL del directorio Documents de la aplicación

  • Crear a partir de ella la URL del fichero mensaje.plist donde están los datos

  • Recuperar el struct con el PropertyListDecoder

Comprobar que cuando paramos el simulador y lo volvemos a poner en marcha se recuperan los datos del .plist.

Ejercicio 2: Preferencias de usuario (2 puntos)

Vamos a probar cómo se podría implementar el ejercicio anterior usando preferencias de usuario, aunque no lo implementaremos del todo, solo lo justo para hacer una prueba.

En el método textViewDidEndEditing del ViewController añade el código Swift que necesites para almacenar el texto y la fecha como preferencias llamadas "texto" y "fecha" respectivamente (con la fecha guarda la propiedad de tipo Date, no la fecha convertida a texto). Al salir de la aplicación se debería crear un archivo .plist dentro del Library/Preferences del sandbox. Usando la app SimSim comprueba que efectivamente se ha creado este archivo.

Por defecto el .plist con las preferencias tiene formato binario, así que si lo abres con un editor de texto no verás el contenido pero sí al abrirlo con Xcode

Finalmente, en el viewDidLoad añade código que recupere las dos preferencias y las imprima con print (no tiene sentido que las ponga en los outlets ya que eso ya lo hacíamos en el ejercicio anterior). Para recuperar la fecha tendrás que usar el método object de UserDefaults.

Fíjate que la ventaja de las preferencias sobre usar directamente plist es que no necesitamos serializar/deserializar explícitamente los datos. A cambio perdemos el control sobre algunos aspectos como el formato de los datos o el momento exacto en que se guardan.

Last updated