Red de conocimiento informático - Aprendizaje de programación - La diferencia entre categorías y extensiones de clase en Objective-C

La diferencia entre categorías y extensiones de clase en Objective-C

En iOS, existe un mecanismo que permite a los usuarios ampliar la funcionalidad de una clase sin herencia, que se llama categoría. No existe ninguna palabra clave en iOS similar a la de C que le permita definir métodos privados y variables privadas, y para definir métodos privados y variables privadas se utilizan extensiones de clase.

Categorías

Las categorías amplían la funcionalidad de una clase sin herencia. Sin embargo, las categorías no pueden agregar propiedades de clase ni variables privadas. Las categorías se pueden usar para extender métodos de clases en Cocoa, o se pueden usar para extender métodos de las clases propias de los usuarios. Cuando miramos el archivo de encabezado del sistema, podemos encontrar definiciones de clases como @interface NSMutableArray (NSExtendedMutableArray), que en realidad es una forma de definición de categorías. Por ejemplo, el siguiente código define una clase NSString para codificación y decodificación Base64.

[cpp] ver copia simple

@interface NSString (Base64)

-(NSString *)encodeBase64

-(NSString * )decodeBase64;

@ end

La definición de una categoría es similar a la definición de una clase. Se definen usando la palabra clave @interface y el nombre de la clase, pero la diferencia es. que la definición de una categoría no es la La clase principal de la que hereda una clase es el nombre de la clase entre paréntesis después del nombre de la clase. La definición del método antes de @end es la misma que la definición del método en la clase. Sin embargo, los atributos no se pueden definir en categorías. El uso de métodos en una clase es exactamente igual que el uso de métodos en la clase original sin ninguna diferencia. Todas las subclases de NSString también pueden usar métodos en ambas categorías de la clase.

Cuando se utilizan categorías, la denominación de los métodos en la categoría es particularmente importante.

Si un método en una clase tiene el mismo nombre que un método en la clase original, no está claro en tiempo de ejecución qué método se llamará cuando el nombre del método sea el mismo, según la documentación para desarrolladores de Apple. En realidad, debería haber una regla para esto. length es un método de NSString y substringFromIndex es un método de la clase NSString. Cuando llamo a estos dos métodos, encuentro que la llamada a la longitud devuelve una llamada al sistema en lugar de mi propia implementación. Al llamar a substringFromIndex, se llama al método que implementé. Por lo tanto, deduzco que cuando el nombre del método en la clase del sistema tiene el mismo nombre que el método en mi propia categoría definida, se llamará al nombre del método del sistema, y ​​cuando el nombre del método en la categoría personalizada tiene el mismo nombre que el método en la categoría del sistema, se llamará el nombre del método del sistema. Utilice la implementación del método en la clase personalizada. Para verificar esta inferencia, seguí adelante y agregué la categoría NSArray para realizar pruebas, y los resultados fueron los mismos que mi inferencia. Aun así, todavía no estamos seguros de que esta conclusión sea correcta y se necesita una mayor verificación.

Agregue dos métodos a la categoría Base64 anterior

[cpp] ver copia simple

-(NSUInteger)length

-( NSString; *)substringFromIndex: (NSUInteger) from;

[cpp] ver copia simple

Implementar estos dos métodos

[cpp] ver copia simple

-(NSUInteger)longitud

{

retorno 40

}

-(NSString *)substringFromIndex: (NSUInteger )desde

{

return @"substring";

}

Al implementar estos dos métodos, aparecerá el método de longitud. Una advertencia indica que este es un método en la clase original y no aparecerá ninguna advertencia para el segundo método porque es un método en la clase NSString. Implemente estos dos métodos usted mismo

Intente llamarlos ahora

[cpp] ver copia simple

NSString *title = @"title"

;

NSLog(@"longitud del título:

NSString *title = @"title";

NSLog(@"longitud del título: d", [longitud del título]);

NSLog(@"subcadena del índice 1: @", [title substringFromIndex: 1]);

La salida es:

[cpp] ver copia simple;

2013-08-16 00:19:.30.678 CategoryTest[12088:c07] longitud del título: 2

2013-08-16 00:19:30.679 CategoryTest[12088:c07 ] subcadena del índice 1: subcadena

No hay problema con la longitud del resultado, la subcadena del método está llamando a un método en la categoría que implementamos.

Revisar definición de clase NSArray

[cpp] ver copia simple

@interface NSArray (ArrayTest)

- (NSUInteger)count <; /p>

- (id) objectAtIndex: (NSUInteger)index;

- (id)lastObject

@end

Los dos primeros Los métodos son los que vienen con NSArray, y el último es un método en la categoría NSArray, que implementa estos métodos a su manera

[cpp] view Plaincopy

@implementation NSArray (ArrayTest)

- (NSUInteger)count

{

retorno 4

}

- (id) objectAtIndex : ( NSUInteger)índice

{

retorno nulo

}

- (id)últimoObjeto

{

return [self objectAtIndex: 0];

}

@end

Ahora llamemos al método

[cpp] ver copia simple

NSArray *array = [NSArray arrayWithObjects:@"objeto 1", @"objeto 2", nil]

NSLog( @" recuento de matriz: d", [recuento de matriz]);

NSLog(@"objeto de matriz en el índice 0:@", [objeto de matrizAtIndex: 0]); (@ "array last object: @", [array lastObject]);

El resultado es el siguiente:

[cpp] ver copia simple

2013- 08-16 00: 19:30.680 CategoryTest[12088:c07] Recuento de matrices: 2

2013-08-16 00:19:30.681 CategoryTest[12088:c07] Objeto de matriz en el índice 0: objeto 1

2013-08-16 00:19:30.681 CategoryTest[12088:c07] El último objeto de la matriz: Objeto 1

La inferencia anterior se basa en la implementación de la clase del sistema categoría. Si es una categoría de su propia clase, no es lo mismo que el sistema. Después de las pruebas, los resultados fueron ligeramente diferentes. Cuando el nombre del método en la categoría tiene el mismo nombre que el método en la clase, se llamará al método en la categoría. Si tiene el mismo método en varias clases, esto tiene que ver con el orden de compilación de las clases, quién compila cuál método es el último. Intenté cambiar el orden de compilación de diferentes categorías y descubrí que las llamadas al método también cambiaron. Puedes escribir una clase tú mismo para probar esto.

Extensión de clase

La extensión de clase es un poco como una definición de categoría, un poco como una categoría sin nombre.

Se define de la siguiente manera

[cpp] ver copia simple

@interface Persona ()

@property (no atómico, fuerte) NSString *address

@end

El código anterior define una extensión de clase para la clase Persona, que se diferencia de las categorías en que no es necesario encerrar el nombre entre paréntesis. Además, las propiedades y variables privadas se pueden definir en extensiones de clase. Otra diferencia es que las extensiones de clase deben compilarse al mismo tiempo que la definición y la implementación de la clase, es decir, las extensiones de clase solo se pueden usar en clases personalizadas y no se pueden agregar a clases del sistema. Los métodos definidos por una extensión de clase deben implementarse en la implementación de la clase. Si define el archivo de extensión de clase por separado y solo define las propiedades, entonces debe incluir el archivo de implementación de clase en el archivo de extensión de clase; de ​​lo contrario, no podrá encontrar los métodos set y get de las propiedades.

En el archivo de implementación Person.m de la clase Person, debes incluir Person_PersionExtension.h. De lo contrario, no podrá utilizar la propiedad de dirección y se bloqueará durante la prueba porque no se puede encontrar el método setAddress. Después de unirte, todo funciona bien.