objective-c - remix - smart contracts ethereum
Ocultar propiedades de acceso público (6)
Debido a que las categorías solo pueden agregar métodos a una clase, no se puede evitar esto al tratar de definir métodos de propiedad en la categoría.
Puede declarar propiedades que se derivan de clases ya existentes. Por ejemplo. Si su clase tiene una firstName
y una lastName
, puede declarar una propiedad llamada fullName
en una categoría @implementation.
@interface Bar (Private)
@property (readonly) NSString *fullName; // Note readonly, you have nothing to write to.
@end
Sin embargo, no puede simplemente @synthesize
esta propiedad, tendría que escribir su propio acceso porque el compilador no tiene idea de dónde quiere obtener este valor.
@implementation Bar (Private)
- (NSString *)fullName {
NSString *returnString = [NSString stringWithFormat:@"%@ %@",
self.firstName, self.lastName];
}
Desde un punto de vista de diseño de clase, no estoy seguro de que la idea de una propiedad privada tenga sentido: personalmente pienso en las propiedades como algo que está expuesto públicamente por una clase.
podría usar la palabra clave @private
en la clase BarLayer para al menos agregar alguna protección a su estado.
Estoy tratando de declarar propiedades que son para uso interno solo en una categoría Private
como tal:
@interface BarLayer (Private)
@property (readwrite, retain) MenuItemFont *menuButton;
@property (readwrite, retain) Menu *menuMenu;
@property (readwrite, retain) LabelAtlas *messageLabel;
@end
Ahora estoy tratando de averiguar dónde se supone que @synthesize
.
Lo intenté:
@implementation BarLayer (Private)
@synthesize menuButton = _menuButton;
@synthesize menuMenu = _menuMenu;
@synthesize messageLabel = _messageLabel;
@end
Aquí, el compilador se queja:
@synthesize no permitido en la implementación de una categoría
Así que intenté ponerlo en mi implementación de BarLayer
, pero aquí no encuentra las declaraciones en la interfaz de BarLayer
.
no se ha encontrado ninguna declaración de propiedad ''menuButton'' en la interfaz
¿Cuál sería la forma correcta?
En realidad, con el último compilador de LLVM, este problema se puede resolver mucho mejor. El método recomendado anteriormente para ocultar todo lo posible sobre sus propiedades fue declarar sus variables en su .h, prefijarlas con una _, declarar una propiedad en una extensión de clase en el .m privado, y @synthesise esa propiedad en su @ implementación.
Con el último LLVM (3.0), puede ir más lejos aún, ocultando todo sobre su propiedad, incluido el respaldo ivar. Su declaración se puede mover a la .m e incluso se puede omitir allí también, en cuyo caso será sintetizado por el compilador (gracias Ivan):
Car.h:
@interface Car : NSObject
- (void)drive;
@end
Car.m:
@interface Car ()
@property (assign) BOOL driving;
@end
@implementation Car
@synthesize driving;
- (void)drive {
self.driving = YES;
}
@end
Encontré una explicación de por qué la síntesis de propiedades está prohibida en categorías, pero cómo puedes usar extensiones de clase en su lugar:
La siguiente información proviene de http://www.friday.com/bbum/2009/09/11/class-extensions-explained/
"La razón por la que se prohibió la síntesis en las categorías fue porque la síntesis requiere almacenamiento y no había manera de declarar el almacenamiento en una categoría de manera eficiente y no se consideró aceptable permitir que una categoría sintetice métodos que luego imitarían directamente los ivars de la clase. Demasiado frágil y feo.
Sin embargo, obviamente también era deseable poder declarar una propiedad que fue de solo lectura pública, pero cuya implementación fue readwrite para propósitos internos a la clase o marco.
Un requisito adicional es que la síntesis de tales propiedades siempre debe ser capaz de sintetizar tanto el establecedor como el captador de forma natural y precisa. Específicamente, al declarar una propiedad como atómica, no hay forma de que el desarrollador pueda escribir manualmente solo la mitad del par del configurador de captadores; la infraestructura de bloqueo no está expuesta y, por lo tanto, no hay forma de garantizar la atomicidad en tal situación.
Las extensiones de clase abordaron este problema con elegancia.
Específicamente, puede declarar una propiedad como:
@interface MyClass : NSObject
@property(readonly) NSView *targetView;
@end
Y, luego, en el archivo de implementación:
@interface MyClass()
@property(readwrite) NSView *targetView;
@end
@implementation MyClass
@synthesize targetView;
@end
¿Resultado final? Una propiedad que se lee públicamente, pero se escribe de forma privada sin abrir propiedades hasta toda la fragilidad divertida asociada con las categorías ".
No puedes usar @synthesize
con una categoría.
Puede hacer esto con una extensión de clase (también conocida como categoría anónima), que es solo una categoría sin un nombre cuyos métodos deben implementarse en el bloque principal @implementation
para esa clase. Para su código, simplemente cambie "(Privado)" a "()" y use @synthesize
en el bloque principal de @implementation
junto con el resto de su código para esa clase.
Consulte la documentación de Apple en las extensiones para obtener más información al respecto. (Aparentemente esto es nuevo en Mac OS 10.5).
EDITAR: Un ejemplo:
// Main interface (in .h)
@interface Foo : NSObject
- (void)bar;
@end
// Private interface (in .m, or private .h)
@interface Foo ()
@property (nonatomic, copy) NSString *myData;
@end
@implementation Foo
@synthesize myData; // only needed for Xcode 4.3 and earlier
- (void)bar { ... }
@end
Otra solución, que es mucho más trabajo, es usar objc_setAssociatedObject
y objc_getAssociatedObject
para falsificar variables de instancia adicionales. En este caso, puede declararlas como propiedades e implementar los configuradores y captadores utilizando los métodos de tiempo de ejecución objc_ * anteriores. Para obtener más detalles sobre esas funciones, consulte la documentación de Apple en el tiempo de ejecución de Objective-C .
Scott Stevenson ( http://theocacao.com/ ) explica en su publicación del blog "Un tutorial rápido de Objective-C 2.0: Parte II" cómo obtener propiedades públicas con establecedores privados . Siguiendo sus consejos, obtendrá una propiedad que es de solo lectura para el público, pero que tiene un setter privado que se puede usar con la sintaxis de puntos. Espero que esto ayude...
Solo quiero agregar mis 2 centavos y dejar que la gente sepa que ES posible agregar propiedades a una clase existente a través de Categorías (no extensiones de clase). Requiere el uso de referencias asociativas, pero en realidad no es tan malo.
Escribí una publicación al respecto aquí si alguien quisiera más detalles.
También hay otra pregunta que aborda este tema, pero es bastante escasa en los detalles .
Aclamaciones