Aprendí algo nuevo al intentar averiguar por qué mi propiedad readwrite declarada en una categoría privada no generaba un setter. Fue porque mi categoría fue nombrado:Minutia en categorías y extensiones de Objective-C
// .m
@interface MyClass (private)
@property (readwrite, copy) NSArray* myProperty;
@end
Si lo cambia a:
// .m
@interface MyClass()
@property (readwrite, copy) NSArray* myProperty;
@end
y mi organismo se sintetiza. Ahora sé que Class Extension no es solo otro nombre para una categoría anónima. Dejar una Categoría sin nombre hace que se metamorfosee en una bestia diferente: una que ahora le da cumplimiento a la implementación del método en tiempo de compilación y le permite agregar ivars. Ahora entiendo las filosofías generales que subyacen a cada una de estas: las categorías se usan generalmente para agregar métodos a cualquier clase en tiempo de ejecución, y las Extensiones de clase generalmente se usan para imponer la implementación de API privada y agregar ivars. Acepto esto
Pero hay pequeñeces que me confunden. Primero, en un nivel alto: ¿Por qué diferenciarse así? Estos conceptos parecen ideas similares que no pueden decidir si son lo mismo o conceptos diferentes. Si son iguales, esperaría que las mismas cosas sean posibles utilizando una Categoría sin nombre como con una Categoría con nombre (que no lo son). Si son diferentes (lo que son), esperaría una mayor disparidad sintáctica entre los dos. Parece extraño decir: "Ah, dicho sea de paso, para implementar una Extensión de clase, simplemente escriba una Categoría, pero omita el nombre. Cambia mágicamente".
En segundo lugar, sobre el tema de la aplicación del tiempo de compilación: si no puede agregar propiedades en una Categoría con nombre, ¿por qué hacerlo convence al compilador de que usted acaba de hacer eso? Para aclarar, lo ilustraré con mi ejemplo. Puedo declarar una propiedad de sólo lectura en el archivo de cabecera:
// .h
@interface MyClass : NSObject
@property (readonly, copy) NSString* myString;
@end
Ahora, yo quiero a la cabeza hacia el archivo de implementación y yo dar acceso de lectura-escritura privada a la propiedad. Si lo hago correctamente:
// .m
@interface MyClass()
@property (readwrite, copy) NSString* myString;
@end
recibo una advertencia cuando no sintetizan, y cuando lo haga, puede establecer la propiedad y todo es color de rosa. Pero, frustrante, si da la casualidad que sea ligeramente equivocada acerca de la diferencia entre la categoría y extensión de clase y trato:
// .m
@interface MyClass (private)
@property (readwrite, copy) NSString* myString;
@end
El compilador está completamente pacificado en el pensamiento de que la propiedad es de lectura-escritura. No recibo ninguna advertencia, y ni siquiera el agradable error de compilación "No se puede establecer el objeto, ya sea propiedad de solo lectura o no encontrado" al configurar myString como lo hubiera hecho si no hubiese declarado la propiedad readwrite en la Categoría. Acabo de recibir la excepción "No responde al selector" en el tiempo de ejecución. Si la adición de ivars y propiedades no es soportada por categorías (nombradas), ¿es demasiado pedir que el compilador juegue con las mismas reglas? ¿Me estoy perdiendo una gran filosofía de diseño?
Creo que quería decir 'readwrite' para las declaraciones de propiedades privadas de myString. Lo edité para reflejar eso; con suerte eso es correcto. –
De hecho lo hice. Gracias. –
Pregunta de Fantasic! –