Cuál es la diferencia entre herencia y Categorías en Objective-C

¿Puede alguien explicarme la diferencia entre categorías y herencia en Objective C? He leído la entrada en Wikipedia y la discusión sobre las categorías allí no parece diferente a la de la herencia. También miré la discusión sobre el tema en el libro “Desarrollo de iPhone abierto” y todavía no lo entiendo.

A veces, la herencia simplemente parece ser más problemática de lo que vale. Se usa correctamente cuando desea agregar algo a una clase existente que es un cambio en el comportamiento de esa clase.

Con una Categoría, solo desea que el objeto existente haga un poco más. Como ya se mencionó, si solo desea tener una clase de cadena que maneje la compresión, no necesita subclasificar la clase de cadena, solo debe crear una categoría que maneje la compresión. De esta manera, no necesita cambiar el tipo de las clases de cadenas que ya usa.

La clave está en la restricción de que las categorías solo agregan métodos, no se pueden agregar variables a una clase usando categorías. Si la clase necesita más propiedades, entonces tiene que ser subclasificada. (Editar: puede usar almacenamiento asociativo, creo).

Las categorías son una buena forma de agregar funcionalidad y al mismo tiempo conformarse con un principio orientado a objetos para preferir la composición a la herencia.

Editar enero de 2012

Las cosas han cambiado ahora. Con el comstackdor LLVM actual y el moderno motor de ejecución de 64 bits, puede agregar iVars y propiedades a las extensiones de clase (no a las categorías). Esto le permite mantener iVars privados fuera de la interfaz pública. Pero, si declaras propiedades para iVars, todavía se puede acceder / cambiar a través de KVC, porque todavía no existe un método privado en Objective-C.

Las categorías le permiten agregar métodos a las clases existentes. Entonces, en lugar de la subclase NSData para agregar sus nuevos métodos de cifrado, puede agregarlos directamente a la clase NSData. Cada objeto NSData en su aplicación ahora tiene acceso a esos métodos.

Para ver qué tan útil puede ser, mira: CocoaDev

Una de las ilustraciones favoritas de las categorías Objective-c en acción es NSString. NSString se define en el marco de Foundation, que no tiene noción de vistas o ventanas. Sin embargo, si utiliza un NSString en una aplicación Cocoa, notará que responde a mensajes como – drawInRect:withAttributes:

AppKit define una categoría para NSString que proporciona métodos de dibujo adicionales. La categoría permite que se agreguen nuevos métodos a una clase existente, por lo que todavía estamos tratando con NSStrings. Si AppKit implementara el dibujo por subclases, tendríamos que tratar con ‘AppKitStrings’ o ‘NSSDrawableStrings’ o algo por el estilo.

Las categorías le permiten agregar métodos específicos de aplicación o dominio a las clases existentes. Puede ser bastante poderoso y conveniente.

Si a usted, como progtwigdor, se le proporciona un conjunto completo de código fuente para una biblioteca o aplicación de códigos, puede volverse loco y cambiar lo que necesite para lograr su objective de progtwigción con ese código.

Desafortunadamente, este no es siempre el caso o incluso deseable. Muchas veces te dan un kit binario de biblioteca / objeto y un conjunto de encabezados para que te las arregles.

Entonces se necesita una nueva funcionalidad para una clase, por lo que podría hacer un par de cosas:

  1. cree una nueva clase completa en lugar de una clase de stock – replicando todas sus funciones y miembros y luego reescriba todo el código para usar la nueva clase.

  2. cree una nueva clase de contenedor que contenga la clase de stock como miembro (composición) y reescriba la base de código para utilizar la nueva clase.

  3. parches binarios de la biblioteca para cambiar el código (buena suerte)

  4. obligue al comstackdor a ver su nueva clase como la anterior y espere que no dependa de un determinado tamaño o lugar en la memoria y puntos de entrada específicos.

  5. especialización de subclase: cree subclases para agregar funcionalidad y modifique el código de controlador para usar la subclase; en teoría, debe haber pocos problemas y si necesita agregar miembros de datos, es necesario, pero la huella de memoria será diferente. Tiene la ventaja de tener tanto el código nuevo como el anterior disponibles en la subclase y elegir cuál usar, el método de la clase base o el método reemplazado.

  6. modifique la clase objc necesaria con una definición de categoría que contenga métodos para hacer lo que desee y / o anule los métodos anteriores en las clases de stock.

    Esto también puede corregir errores en la biblioteca o personalizar métodos para nuevos dispositivos de hardware o lo que sea. No es una panacea, pero permite agregar el método de clase sin recomstackr la clase / biblioteca que no ha cambiado. La clase original es la misma en código, tamaño de memoria y puntos de entrada, por lo que las aplicaciones heredadas no se rompen. El comstackdor simplemente coloca los nuevos métodos en el tiempo de ejecución como pertenecientes a esa clase y anula los métodos con la misma firma que en el código original.

    un ejemplo:

    Tienes una clase Bing que se envía a un terminal, pero no a un puerto serie, y ahora eso es lo que necesitas. (por alguna razón). Tienes Bing.h y libBing.so, pero no Bing.m en tu kit.

    La clase Bing hace todo tipo de cosas internamente, ni siquiera sabes todo, solo tienes la API pública en el encabezado.

    Eres inteligente, por lo que creas una categoría (SerialOutput) para la clase Bing.

     [Bing_SerialOutput.m] @interface Bing (SerialOutput) // a category - (void)ToSerial: (SerialPort*) port ; @end @implementation Bing (SerialOutput) - (void)ToSerial: (SerialPort*) port { ... /// serial output code /// } @end 

    El comstackdor obliga a crear un objeto que se pueda vincular con su aplicación y el tiempo de ejecución ahora sabe que Bing responde a @selector (ToSerial 🙂 y puede usarlo como si la clase Bing se hubiera creado con ese método. No puede agregar solo métodos de miembros de datos y esto no tiene la intención de crear tumores gigantescos de código adjuntos a las clases base, pero tiene sus ventajas sobre los lenguajes estrictamente tipados.

Creo que algunas de estas respuestas al menos apuntan a la idea de que la herencia es una forma más pesada de agregar funcionalidad a una clase existente, mientras que las categorías son más livianas.

La herencia se usa cuando se crea una nueva jerarquía de clases (todas las campanas y silbatos) y posiblemente traiga mucho trabajo cuando se elige como el método para agregar funcionalidad a las clases existentes.

Como dice alguien más aquí … Si está usando la herencia para agregar un nuevo método, por ejemplo, a NSString, debe ir y cambiar el tipo que está utilizando en cualquier otro código donde quiera usar este nuevo método. Sin embargo, si usa categorías, simplemente puede llamar al método en los tipos NSString existentes, sin crear subclases.

Los mismos fines se pueden lograr con cualquiera de los dos, pero las categorías parecen ofrecernos una opción que es más simple y requiere menos mantenimiento (probablemente).

¿Alguien sabe si hay situaciones en las que las categorías son absolutamente necesarias?

Una categoría es como un mixin: un módulo en Ruby, o algo así como una interfaz en Java. Puedes pensarlo como “métodos desnudos”. Cuando agrega una Categoría, está agregando métodos a la clase. El artículo de Wikipedia tiene buenas cosas .

La mejor manera de ver esta diferencia es que: 1. herencia: cuando quiera convertirlo exactamente en su camino. ejemplo: AsyncImageView para implementar la carga diferida. Lo cual se hace heredando UIView. 2. categoría: solo quiero agregarle un sabor extra. ejemplo: queremos reemplazar todos los espacios del texto de un campo de texto

  @interface UITextField(setText) - (NSString *)replaceEscape; @end @implementation UITextField(setText) - (NSString *)replaceEscape { self.text=[self.text stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]; return self.text; } @end 

— Agregará una nueva propiedad al campo de texto para que pueda escapar de todos los espacios en blanco. Al igual que agregarle una nueva dimensión sin cambiar completamente su camino.