Home » Guías » Cómo leer un plist en Swift 3 de manera nativa
Leer plist en Swift 3

Cómo leer un plist en Swift 3 de manera nativa

Es uno de los grandes errores que cometen aquellos que entran en el mundo de Swift: intentar hacerlo todo como se hacía en Objective-C. Y esta funcionalidad específica es uno de los errores más comunes. Con Objective-C, el tipo NSDictionary tiene un constructor contentsOf que nos permite carga los datos de un fichero y esto parsea automáticamente un fichero de lista de propiedades (o plist) como diccionario.

Pero hacer esto en Swift (que puede hacerse) es un error enorme. Primero porque no estamos usando la especificación nativa del lenguaje y si nos vamos a otro sistema operativo usando Swift Open Source no vamos a poder usarlo porque el tipo NSDictionary no existe. Segundo, porque los diccionarios en Objective-C son objetos por referencia mientras que en Swift son tipos del sistema por valor, mucho más eficientes en su gestión en memoria y funcionamiento. Y tercero: estamos en Swift, así que hagámoslo al estilo Swift.

Vamos a suponer que tenemos en el bundle de nuestro proyecto (o incluso en un playground, que también se puede hacer ahí) un fichero .plist que queremos cargar y que directamente se cargue en un diccionario. La clave para hacerlo en Swift está en recuperar los datos en bruto de dos posibles maneras: podemos usar el constructor del tipo Data del sistema con una URL que previamente apuntará al fichero o usar la clase FileManager con el método contents de su instanciación de tipo singleton, default. Una u otra son métodos válidos, pero el objetivo es obtener los datos en bruto del plist dentro de una variable Swift.

Vamos a suponer que queremos cargar un fichero .plist con información crítica de alto secreto que corresponde a una lista de Pokémons. Un fichero llamado poke-info.plist que como hemos dicho tenemos en nuestro bundle de nuestro proyecto o en la carpeta Resources de nuestro playground.

En ambos casos hemos de prevenir errores, solo que en el primer caso hacemos un doble enlace opcional recuperando la ruta dentro del Bundle para acceder a nuestro fichero y luego recuperamos el contenido a través del método FileManager.default.contents(atPath:). En el segundo caso, en vez de usar el método path de Bundle.main que devuelve una cadena, hemos de recuperar un dato de tipo URL por lo tanto usamos el método url del mismo Bundle.main. Aunque como vemos, para el segundo ejemplo, el constructor del tipo Data(contentsOf:) es de tipo throw, lo que indica que puede propagar errores y hemos de acotarlo dentro de un do, try y catch para controlar los posibles que pudiera haber.

Una vez elegido el método que más rabia nos de (o el que más nos guste) para cargar el contenido del plist debemos parsearlo y cargarlo en un diccionario nativo en Swift 3. Para ello usamos el objeto PropertyListSerialization que nos permite hacer serializaciones de ficheros plist. Este lo que hace, básicamente, es recoger el dato en bruto, reconocer su correcto formato como fichero y cargar los datos en un diccionario. Para ello usamos el constructor PropertyListSerialization(from:options:format), donde los dos últimos parámetros podemos dejarlos vacíos y con ello el sistema detectará automáticamente el tipo.

El primer método de carga, donde hacemos uso de los opcionales con FileManager, luego necesita crear igualmente un ámbito do, try y catch ya que el constructor que usamos del objeto PropertyListSerialization es un método de tipo throw y por lo tanto, hemos de controlar los posibles errores. Pero como vemos, solo tenemos que llamarlo con la constante donde hemos cargado el bruto, pasamos options como un array vacío y format como nil. Aquí podríamos indicar una serie de enumeraciones que nos configurarían el formato o la forma de acceder al fichero, pero por ahora no nos interesa y lo dejamos tal cual está.

Como podemos ver, tenemos que forzar lo que devuelve este constructor a un tipo diccionario [String:AnyObject], donde tendremos la clave del plist y el dato en cada registro del propio diccionario. A partir de aquí solo tenemos que pedir las claves del raíz del fichero que queramos y hacer un cast opcional con as? o forzado (según elijamos) con as! para convertir el AnyObject donde están los datos en el correspondiente dato que realmente sea. Aunque sea un AnyObject, si lo guardamos en un array de Swift (si es el caso), al ser tipos por valor hará la conversión de forma automática.

Como podemos ver, en este último caso de carga, hemos directamente extraído un array que teníamos en el plist bajo la clave "pokemons". Lo forzamos a as! [String] porque ya sabemos previamente que el tipo coincide y por lo tanto tendríamos cargados los datos para trabajar sin problema.

A mi parece más intuitivo que el método con Objective-C, y más o menos similar en cuanto a cantidad de líneas o complicación. Pero como hemos dicho, mejor hacerlo a la manera Swift 3.

Si tenéis cualquier duda o petición para saber cómo realizar alguna tarea o función en Swift 3 o derivados, no dudéis en poneros en contacto con nosotros a través de cualquiera de las múltiples vías de redes sociales o el formulario de contacto de la web. Estaremos encantados de atender vuestras peticiones. Un saludo y Good Apple Coding.

Acerca de Julio César Fernández

Analista, consultor y periodista tecnológico, desarrollador, empresario, productor audiovisual, actor de doblaje e ingeniero de vídeo y audio.

Otras recomendaciones

ARKit

Analizando ARKit

Realizamos un análisis de ARKit, sus posibilidades, cómo funciona y lo comparamos con las Microsoft Hololens para ver el alcance de sus posibilidades. Un análisis en detalle incluyendo algunas pruebas en vídeo que hemos realizado mientras preparamos el curso de ARKit en Apple Coding Academy que verá la luz en septiembre, una vez tengamos versión final de esta interesante plataforma.