Manejador de Dependencias en iOS (Parte I)

Matias Spinelli
Wolox
Published in
10 min readOct 10, 2019

--

Seguramente has escuchado algo sobre gestores de dependencias como Cocoapods, Carthage o Swift Package Manager. Quizás, los estés usando y no sabes bien para qué sirven o cómo funcionan.

En esta guía vamos a aprender un poco sobre ellos, cómo aprovecharlos, algunos errores comunes y cómo solucionarlos. No pretendo obligarte a usar el que más me gusta a mí, cada desarrollador es libre de usar el que prefiera, solamente voy a exponer mi experiencia.

Esta guía va a tener 3 partes, en esta primera parte vamos a hablar de CocoaPods.

Un poco de teoría

En su página web CocoaPods se define así: “CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects”. Esto puede traducirse como un gestor de dependencias en nuestro Xcode. CocoaPods se encarga de integrar esas dependencias o librerías externas a nuestro proyecto facilitándonos el trabajo.

Para hacer más simple esta guía vamos a tratar a un framework y a una librería como si fueran lo mismo ya que se integran de la misma forma a nuestro proyecto. Lo único en lo que difieren es su contenido así que esa discusión de la que muchos disfrutan, la dejamos para una próxima vez.

Como estamos usando CocoaPods, de ahora en adelante vamos a referirnos a ese framework o librería como “Pod”.

¿Cómo usar un Pod?

Vamos a usar Alamofire como ejemplo.

  1. Instalamos CocoaPods.
    En caso de no tenerlo ya instalado. Abrimos una terminal y escribimos:
$ sudo gem install cocoapods

2. Creamos un Proyecto en Xcode.

3. Creamos un Repositorio en GitHub (por ejemplo).

4. Abrimos una terminal y seguimos los pasos que nos indican en GitHub:

5. Integramos nuestro primer Pod escribiendo en la terminal (root del proyecto):

$ pod init

Esto va a crear un archivo llamado Podfile. Lo podemos abrir con un TextEdit o con el mismo Xcode:

Borramos las líneas que tienen comentarios (son las que empiezan con #) para dejarlo más limpio y que se entienda mejor. También borramos los targets de Test y UITest ya que para este ejemplo no los vamos a utilizar.

Escribimos: pod Alamofire

Nos tiene que quedar así:

Cualquier duda que tengamos sobre Alamofire, podemos siempre mirar en su GitHub que tiene una muy buena explicación sobre cómo integrarlo.

Ahora lo más divertido…

En la terminal escribimos:

$ pod install

y disfrutamos!

Esto puede tardar un tiempo…Después, veremos que nos informa que terminó de instalar y nos creó una carpeta llamada “Pods” donde van a estar todos los pods que instalemos. Se debería ver así:

En la carpeta de nuestro proyecto, podemos ver que se creó un workspace, esto es porque el Pod modifica la estructura del proyecto. De ahora en más vamos a abrir siempre el .xcworkspace y no el .xcodeproj como hacíamos antes. Al abrirlo nos vamos a dar cuenta de que además de nuestro proyecto, tenemos el proyecto Pods con todos los archivos públicos de Alamofire y que ya lo podemos usar tranquilamente.

Ahora que ya sabemos cómo instalar un pod, vamos a hacer un Pod nosotros…

¿Cómo crear un Pod?

Vamos a aprender a hacerlo de forma difícil para tratar de entender paso a paso y en próximas entregas aprenderemos algunos atajos para simplificar.

Para que el ejemplo tenga sentido sin complicarnos la vida vamos a hacer solamente un viewController con una imagen, lo vamos a subir como Pod y luego lo usaremos desde el proyecto que acabamos de crear.

Comenzamos igual que antes…

1. Creamos un Proyecto

Con un ViewController simple, con un label y una imagen.

En el main.Storyboard, insertamos nuestra vista a un UINavigationController, a esa vista le agregamos un botón con un método que redireccione a nuestro nuevo ViewController:

Lo ejecutamos en el simulador para probar que todo funcione perfecto. Debería quedarte algo así:

2. Creamos un repositorio

Lo creamos igual que antes y subimos todo al repositorio.

3. Creamos un Podspec

Vamos a una terminal y escribimos:

$ pod spec create WolmoView

Esto crea un archivo nuevo que podemos editar con TextEdit o con Xcode. Al abrirlo, nos encontramos con un montón de líneas con comentarios. Si entendemos un poco de inglés, nos explican para qué sirve cada ítem, también cuales son opcionales y cuáles obligatorias:

Podemos borrar todo lo que tiene comentarios y quedarnos solo con las cosas que necesitamos, para que quede más limpio y fácil de leer. Es decir, para que nos quede así:

Vamos a ver que es cada item…

spec.name es el nombre de nuestro pod.

spec.version es el número de versión de nuestro Pod. Más adelante veremos que tenemos que crear un “tag” para dicho número y lo usaremos al momento de instalar nuestro Pod en otro proyecto, para cada modificación que hagamos en nuestro Pod debemos cambiar también el número de versión.

spec.summary es el resumen de nuestro pod.

spec.description es una breve descripción de nuestro pod.

spec.homepage podríamos poner nuestra propia web, pero con poner la url de git es suficiente.

spec.license todo pod que hagamos tiene que tener una licencia para poder ser utilizado. Existen muchos tipos de licencias (acá una lista de las licencias).

La más común en estos casos, y la que vamos a utilizar, es la licencia MIT que es la que permite que otras personas utilicen nuestro código, en este caso nuestro Pod (acá más información). Tenemos que crear un archivo llamado LICENSE y ponerlo en nuestro pod en el repo y especificarlo en esta línea del podspec.

S pec.author somos nosotros, nombre y apellido y nuestro email.

spec.source lo dejamos casi como viene por default pero modificamos la url para que apunte a nuestro git, a nuestro repo que acabamos de subir.

spec.source_files tenemos que asegurarnos de que esté bien la carpeta donde queremos que se busquen los archivos que vamos a subir a nuestro pod. En este caso solamente queremos subir lo que está dentro de “WolmoViewController” ya que no queremos subir, por ejemplo, el “AppDelegate.swift”.

spec.resources nos aseguramos de que se busquen en esas carpetas todos los archivos de recursos que utilizamos en nuestro pod, imágenes, xibs, storyboards, etc.

Finalmente, esas dos últimas líneas las agregué en este pod en particular ya que estoy trabajando con xcode 10.3 y el proyecto lo creamos para su última versión de iOS y de Swift. Por eso en spec.ios.deployment_target especificamos el sistema operativo mínimo requerido y en spec.swift_version el mínimo de versión de Swift.

4. Creamos una licencia

En la terminal escribimos:

$ touch LICENSE.md

Podemos abrir el archivo con un TextEdit. Ya que por el momento no tenemos dependencias de otras librerías podemos copiar de cualquier license de otros proyectos o crear uno usando un template como éste.

5. Validar el Podspec

Ahora sí, volvemos a la terminal y escribimos:

$ pod spec lint

Como nos decía al principio de este podspec (que borramos en el paso 3), esto sirve para validar el podspec. Esto puede tardar bastante, y puede fallar bastante también, pero si leemos lo que nos responde, podremos corregirlo y lograr que funcione:

¡El color verde significa que todo está bien! Ya está casi listo nuestro pod…

6. Subimos los cambios al repositorio

Lo podemos hacer en la terminal, o con el Xcode o con alguna herramienta con la cual estemos cómodos para subir todo al repositorio.

$ git add .$ git commit -m ‘podspec’$ git push

Tenemos que crear la etiqueta que especificamos en el spec.version para que nuestro pod vaya a buscar la versión correcta.

En la terminal escribimos:

$ git tag 0.0.1$ git push — tags

¡Ahora sí, está todo casi listo!

7. Integramos nuestro pod nuevo en el proyecto:

Volvemos al Podfile del primer proyecto que creamos, (MSFCocoaPods) donde integramos Alamofire y ahí mismo agregamos:

pod ‘WolmoView’, :git => ‘https://github.com/matiasspinelli4/WolmoView

En la terminal (de este proyecto * no olvidarse de hacer $ cd MSFCocoaPods *).

Escribimos de nuevo:

$ pod install

Vemos algunas advertencias, sobre la versión de iOS.

Tenemos que asegurarnos de incluir en nuestro proyecto los pods que compilen para la misma versión del sistema operativo y para la misma versión del lenguaje Swift que la que estamos trabajando. ¡Estos detalles son los que un buen pod debe tener en su Readme!

Les comparto un ejemplo de buen ReadMe:

Abrimos el workspace y vemos que además de Alamofire (que teníamos integrado desde antes) ya tenemos integrado también nuestro pod y podemos usarlo.

Vemos también que se han agregado algunos archivos extraños en SupportFiles. Por el momento no debemos darles importancia pero tenemos que entender que son utilizados por Cocoapods para cargar nuestro pod. Por eso son importantes y no debemos borrarlos.

Luego, agregamos el “import” de WolmoView a nuestro ViewController como hicimos con Alamofire. Vamos a replicar lo mismo que hicimos en el ejemplo del Pod pero esta vez usándolo desde nuestro proyecto y tomando el ViewController del Pod.

Creamos un botón en el Main.storyboard y un @IBAction que redireccione a nuestro WolmoViewController que está dentro del pod:

¡UH! ¿Pero qué pasa? ¿Por qué no funciona?

Esto es un error muy, pero muy, común.

¡MUY IMPORTANTE!

Para evitar este error tenemos que aprender sobre Access Control. En Swift tenemos 5 niveles de acceso a nuestras clases, funciones y variables: Open, Public, Internal, Fileprivate y Private. No queremos irnos del eje de esta guía así que les recomiendo revisar la web de AccessControl que explica muy bien para qué sirve cada uno y cuáles son sus diferencias.

8. Modificamos los archivos que sean necesarios dentro del Pod.

Entendemos que para poder acceder desde nuestro proyecto al ViewController del Pod, tenemos que hacer esa clase pública:

9. Modificamos el Podspec y subimos al repositorio

Para poder comprobar que solucionamos nuestro error tenemos que modificar el podspec, crear un tag nuevo y subir todo al repositorio.

Sí, esto es lo que más molesta, a cada cambio que hagamos por más pequeño que sea, tenemos que repetir estos pasos.

Volvemos a MSFCocoaPods (* no se olviden de hacer $ cd MSFCocoaPods *) y en la terminal escribimos

$ pod update 

para que actualice a la nueva versión del pod que acabamos de subir:

Vemos cómo se ha integrado la versión 0.0.2. Ahora encuentra el WolmoViewController:

Lo ejecutamos en el simulador y ¡BOOM! Falló.

Leemos lo que nos dice:

2019–08–20 22:38:04.912257–0300 MSFCocoaPods[59388:4308848] *** Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Could not load NIB in bundle: ‘NSBundle </Users/matiasspinelli/Library/Developer/CoreSimulator/Devices/17082FCF-A079–4971-B28F-725F196117FD/data/Containers/Bundle/Application/037557CD-8B0D-4CC4-A93A-9C465C9A5682/MSFCocoaPods.app> (loaded)’ with name ‘WolmoViewController’’

Estamos tan acostumbrados a no especificar el bundle, que lo escribimos como bundle: nil o Bundle.main. En este caso sí es importante especificar el bundle porque está queriendo buscar el nib de WolmoViewController en nuestro proyecto (no en el pod) y al no encontrarlo crashea. Vamos a tener que especificar el Bundle, ese es otro de los errores más comunes que suceden en este tipo de creaciones de pods. En este caso, lo podemos solucionar muy fácilmente:

Lo ideal sería que en nuestro pod WolmoViewController tenga su propio init con esos parámetros para que dentro del proyecto no se tengan que hacer estas cosas y el pod pueda ser utilizado por cualquier proyecto.

Recapitulando…

En esta pequeña pero larga guía, pudimos crear un pod e integrarlo a otro proyecto de la misma manera que lo podría integrar otra persona en su proyecto.

Nos encontramos con dos de los errores más comunes que suceden al crear pods, access control y Bundles. Este último aplica también para todos los recursos que tengamos dentro del Pod, imágenes, fuentes, xibs, storyboards, etc.

Subimos 2 tags (o 2 releases) del Pod dentro de nuestro GitHub para poder utilizar el pod en el proyecto ya que por lo general en el ejemplo del pod todo funciona correctamente, pero los errores comienzan a aparecer cuando lo importamos en un proyecto diferente.

En la segunda parte de esta guía vamos a continuar un poco más con CocoaPods viendo de qué manera podemos mejorar el manejo de versiones para que solamente subamos al repositorio un tag una vez que estemos seguros de que funciona bien. Para eso vamos a modificar el proyecto de ejemplo (o Demo) del Pod y también vamos a experimentar qué pasa cuando los repositorios son privados o cuando una dependencia que quiero integrar a mi proyecto tiene a su vez una sub-dependencia. Por último, te invito a ver el código aquí y aquí.

banner

--

--