¡Atención! Este sitio utiliza cookies.
Si no cambias la configuración de tu navegador, aceptas su uso.

Semillas de Cacao: Las Categorías

Si estás enamorado de Cocoa y todavía sigues subclasificando (‘extendiendo’ para los paganos) clases una y otra vez, “you are doing it wrong”. Bromas aparte, las categorías son una manera ultrasencilla de añadir funcionalidad a una clase, y al tiempo para evitar caer en el alcoholismo. Si todavía no te atrevías con ellas, aquí vamos a perderles el miedo.

The Matrix

¿Viste la primera película de Matrix? (la segunda es aceptable, para la tercera tienes que haberte puesto fino de los M&Ms esos que venden a las 4 de la mañana). Recordarás que al principio de la trama Neo descubre que hasta el momento vivía en un mundo virtual, regido a unas normas y comportamiento concretos (inmutables): al ‘despertar’ ya no es usuario de Matrix, sino una especie de pseudo-programador que tiene acceso a todas las APIs privadas del sistema.

Bueno, yo entendí eso.

La cuestión es que, por mucho descubrimiento que haya hecho, cuando vuelve a introducirse en el sistema, se le compila con los mismos atributos de la última vez. Su mente real se ha proyectado en Matrix de nuevo pero no es suficiente para combatir a Elrond Smith y sus secuaces; de modo que tiene que añadir nuevos conocimientos a los que ya tiene. Para ello no le pagan una academia, ni le dan un libro, ni va a un dojo a practicar Kung-Fu. Aquí se dejan de mariconadas: le meten un Thunderbolt™ oxidado por la nuca y le instalan lo que necesita saber en un santiamén.

ya sé kung-fu

¿Que quieres un curso avanzado sobre programación en WebOS? Buscamos el programa y calambrazo que te crió.

Las categorías son algo similar. Sirven para definir métodos adicionales a una clase preexistente, incluso aunque no tengas acceso a ella (esto está traducido directamente de la documentación de Apple). ¿Qué quiere decir esto? Que a cualquier clase conocida le puedo pasar por un cable todos los métodos que a mí me dé la gana.

¿Que quieres que UIImage aprenda Kung-Fu? ¡No hay problema! En seguida veremos cómo. Y sí, he usado ‘UIImage’ y ‘Kung-Fu’ en la misma frase.

¿Por qué categorías y no herencia?

Puede que estés pensando: “si puedo hacerlo por herencia, ¿para qué canastos liarme con categorías? Me voy a lo sencillo, que además ya lo conozco”.

En realidad es más sencillo añadir métodos mediante categorías una vez que sabes de su existencia, para qué son y cómo funcionan. Ya sabes que existen, ahora nos queda saber para qué son.

Cuando se trata de heredar lo que se procura es crear una clase más específica, con más atributos y métodos que la que estamos extendiendo. Si la intención es esa: añadir propiedades y añadir métodos (o sobreescribir algunos que ya estaban en la clase superior), entonces perfecto. Pero, ¿qué ocurre cuando tengo una clase a la que simplemente le quiero añadir 4 métodos para mejorar algún aspecto de la misma? ¿Voy a heredar y a montarme ese tinglado sí o sí? Ten en cuenta que una clase heredada no será nunca exactamente como la clase de la que hereda, es decir, una Berlina pasará como un Coche, efectivamente, pero se la tratará como Coche. Si deseas acceder a las propiedades de la Berlina te encontrarás con esa clase se ha vuelto bastante opaca desde que la disfrazaste de Coche. Según qué casos, puedes darle al compilador gato por liebre. Esto está bien porque una Berlina ‘es un tipo de Coche‘, y por tanto tendrá atributos propios. No sería así si siempre manejamos la misma clase pero solo queremos utilizar funciones añadidas.

Homer Simpson BBQ

La herencia añade complejidad a la arquitectura de tu código.

Así que, ¿y si solo queremos añadir métodos? ¿y si la nueva clase no necesita heredar funcionalidad, sobreescribirla ni mucho menos declarar atributos propios? ¿Y si solo queremos una clase que permita reproducir música? En el fondo, solo queremos que el Coche diga ‘ya sé cómo reproducir música’. Para eso creamos una clase categoría sobre la clase Coche.

Una ventaja adicional de utilizar categorías (y que comparte con el patrón del delegado) es que no necesitamos conocer la clase sobre la que categorizamos, es más, podríamos no tener ni siquiera acceso a ella, así que, si no podemos ver qué narices hay dentro, ¿no aumentan las posibilidades de cagarla? La respuesta es bastante.

Un caso claro es la clase NSArray de Cocoa, ya que, aunque nosotros la utilizamos para casi cualquier tipo de colección, bajo el capó sucede una historia bien diferente: según la situación NSArray hará uso de sus subclases para almacenar los datos de manera más óptima. Si echabas de menos las Listas en Objective-C, ya sabes dónde las han metido. ¿Sigues pensando en utilizar la grandiosa herencia? Haz lo que quieras, pero más vale que sepas lo que haces…

La idea es que si tenemos dos clases, A y B:

  • ‘A’ funcione independientemente de ‘B’, y además le sea indiferente. ‘A’ nunca se toca y va ‘a su bola’.
  • ‘B’ necesita saber cosas que ya sabe ‘A’.

Crearíamos una categoría de ‘A’ llamada “A+B”, donde en ‘B’ metemos todo aquello que queremos añadir a ‘A’.

categorias

Creando una clase categoría

Crear una categoría es ridículamente sencillo. Entramos en un proyecto de Xcode (cualquiera nos vale, incluso uno vacío) y vamos al asistente para crear un nuevo archivo (Archivo->Nuevo->Archivo o con CMD+N). Filtramos por clases de Cocoa/CocoaTouch, donde accedemos de normal para crear una nueva clase de lo que sea.

Objective-C Category Xcode asistente

Más claro agua

Al seleccionar la opción de Categoría de Objective-C (o Swift) pasaremos a otra ventana en la que se nos pide el nombre que le vamos a dar, así como la clase que vamos a ‘categorizar’.

Escribimos “KungFu” en el nombre y “UIImage” en la clase a categorizar. Guardamos. El resultado son 2 archivos h y .m llamados “UIImage+KungFu”.

categories_xcode2

Perfecto ¡Ya tenemos nuestra clase categoría!

Vamos a enseñar KungFu a una imagen de UIKit

O al menos que lo parezca. Ya se sabe que por mucho que uno diga que sabe KungFu…

Vamos al .h de la clase y escribimos el siguiente método:

En el fichero de implementación escribimos lo propio.

No es que haga mucho, pero bueno, al menos puede achantar a los NSStrings…

 UIImage is KungFu fighting….

Dirijámonos a AppDelegate, por ejemplo, aunque nos vale cualquiera, e importamos la categoría. Puedes hacerlo en el archivo Prefix.pch si sabes cómo (es más divertido).

Escribe “[UIImage ” en cualquier línea de cualquier método, y a continuación envía el mensaje doKungFu. ¿Cómo? ¿La imagen hace KungFu?

Recuerda que hemos definido el método como estático, quiero decir… de clase, ¡de clase! Por eso no ha sido necesario crear una instancia primero.

Ejecuta y verás que, aunque no lo grita a los cuatro vientos, lo dice lo suficientemente claro como para que se enteren todas las instancias del runtime. A ver quién se mete con UIImage ahora…

Esta es una implementación estúpida, absurda y trivial, pero puedes aplicarla a cualquier proyecto con cualquier cosa que se te ocurra, no un simple NSLog(“”);

Usos Comunes

  • Separar una clase en archivos más ligeros. ¿Alguien ha dicho ‘lighter view controllers’?
  • Dar funcionalidad añadida a clases del sistema sin alterar su comportamiento interno.

¿A alguien se le ocurren más usos? Si tienes alguna corrección o duda, siéntete libre a expresarla en los comentarios.

¿Te ha gustado? También me hará feliz saberlo. Acepto donaciones y tal.

Escrito por Miguel Hernández Jaso

Autor del blog. Desarrollador especializado en iOS.

4 respuestas a “Semillas de Cacao: Las Categorías”

  1. Llevo leyendo tu blog un par de días y me han parecido muy graciosas tus explicaciones y muy útiles. Te mereces un café/copita. ¿Donativos? PAYPAL o Twyp.

    • La verdad es que estas opiniones tienen mucho más valor que el café que me estoy tomando ahora mismo. Distribuir y dar a conocer estos artículos es para mí lo más importante, así que en ese sentido, ya me siento pagado. De hecho, como habrás observado, este blog no se alimenta de publicidad 😉

  2. Me gustaría aportar, que ahora en Xcode 6 y 7 las Categorias no están cocoaTouch
    ahora hay que ir a :

    1º File -> New -> File
    2º Seleccionar “Objective-C file”
    3º Debajo te permite elegir entre Category, Protocol, or Extension

    y yásta!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Mi Gobierno me obliga a decirle que utilizo 'cookies' en mi página. Si continúa navegando, quiere decir que está conforme con ello.