2011-04-28 12 views
13

He revisado un montón de publicaciones sobre este tema. Quizás no me topé con "el uno" y alguien me señalará en esa dirección. La pregunta es simple y probablemente tiene una respuesta simple.¿Cómo declarar variables de instancia y métodos no visibles o utilizables fuera de la instancia de clase?

Si tiene dos ivars, por ejemplo, "public_ivar" y "private_ivar", ¿dónde/cómo debería declararlos para que lo público sea público y lo privado no se exponga de forma alguna a nadie que mire el encabezado? ¿archivo?

La misma pregunta en el caso de "public_method" y "private_method".

Me gustan los archivos de encabezado limpio (en otros idiomas) que solo exponen los métodos y ivars que deseo que alguien más vea. Debería poder publicar su archivo de encabezado y no correr el riesgo de que alguien acceda a algo que no debería. ¿Cómo se hace eso en el objetivo C?

Por ejemplo, supongamos que decido que necesito usar un ivar para mantener un registro de algunos datos, un contador o algo así, entre varios métodos de clase que necesitan acceso a esta información. Si ese ivar se declara convencionalmente en el encabezado debajo de @interface, su existencia se anuncia públicamente y cualquiera puede usarla para crear una instancia de la clase. El escenario ideal sería que este ivar no sería visible en absoluto fuera de la implementación de la clase.

Respuesta

17

Puede declarar variables de instancia o propiedades declaradas en una extensión de clase. Como una extensión de clase se declara en un archivo de implementación (es decir, no un archivo de encabezado), no será visible para alguien que inspeccione el archivo de encabezado. Por ejemplo, en el archivo de cabecera:

@interface SomeClass : NSObject 
@end 

y en el archivo de implementación:

@interface SomeClass() 
@property (nonatomic, assign) int privateInt; 
@end 

@implementation SomeClass 

@synthesize privateInt; 
… 
@end 

o

@interface SomeClass() { 
    int privateInt; 
} 
@end 

@implementation SomeClass 
… 
@end 

Tenga en cuenta que no hay nada que impida el acceso a las variables de instancia extensión privada/clase (o los métodos de acceso para las propiedades declaradas en una extensión de clase) durante el tiempo de ejecución. He escrito un post bastante detallada acerca de esto como una respuesta a otra pregunta sobre el desbordamiento de pila: Does a private @property create an @private instance variable?

Editar: Las variables de instancia en extensiones de clase se presentaron en la WWDC sesión de 2010 144.

Editar: "Al usar el compilador Clang/LLVM 2.0, también puede declarar propiedades y variables de instancia en una extensión de clase".

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html#//apple_ref/doc/uid/TP30001163-CH20-SW1

+0

Bien, voy a echar un vistazo a esto. Estoy trabajando con Algoritmos Genéticos y Redes Neuronales. Las clases terminan con montones de variables que se necesitan internamente. Muy pocos de estos realmente necesitan visibilidad en el nivel del archivo de encabezado. ¿Es su primer ejemplo del archivo de implementación para iOS4 + (ya que no declara int privateInt; antes de la declaración @property)? –

+0

@Martin No estoy seguro de cuándo Objective-C 2.0, que permite la creación automática de variables de instancia de respaldo, estuvo disponible para iOS. –

+0

@Martin [Esta página en el sitio web de Apple] (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtVersionsPlatforms.html%23//apple_ref/doc/uid/ TP40008048-CH106-SW1) no incluye una versión específica de iOS. –

2

Puede usar @private para especificar que los ivars son privados. Sin embargo, no hay forma de hacer que un método sea privado. Incluso si el método no figura en el archivo de encabezado, si alguien conoce el nombre y los argumentos, pueden llamarlo.

+0

Según tengo entendido, @private realmente no hace nada si tiene @property declaraciones (setters y getters). Ni siquiera quiero que la función ivar o miembro privado esté en el encabezado. Bajo la suposición de que nadie los conoce, deberían permanecer invisibles (solo tratar de mantener honesta a la gente honesta, si quieres cavar puedes descubrir cualquier cosa). Simplemente creo que es "sucio" tener todas estas cosas en el encabezado que son totalmente irrelevantes para otras partes de una aplicación. –

+1

@Martin: una propiedad no es un ivar. En cuanto a ocultar ivars en el encabezado, puedo pensar en dos opciones: podría hacer que el único ivar sea un puntero a una estructura que se declara en otra parte, o podría tener todas las instancias como subclases privadas (en la línea de lo que Apple hace con grupos de clase). – Anomie

+0

Culpable de ser flojo con el lenguaje. Entiendo que @property simplemente crea el setter subyacente y el código getter. ¿Hace algo más? –

4

Uso class extensions a añadir a una clase en su archivo de implementación. Una extensión de clase es básicamente una categoría sin nombre con algunas bonificaciones: las propiedades declaradas en ella se pueden sintetizar y todo lo que se declare debe estar en la implementación principal, por lo que el compilador puede verificar para asegurarse de que no se perdió una implementación. Debe poner la extensión de clase antes de su implementación. No puede agregar variables de instancia directamente en una extensión de clase, pero puede agregar propiedades.Cuando se sintetizan los descriptores de acceso para las propiedades que no tienen variables de instancia correspondientes, el nuevo tiempo de ejecución (os x 10.5 y posterior y todas las versiones de iOS, creo) crearán las variables de instancia automáticamente. Esto significa que no puede crear sus propios accesores, a menos que coloque la variable de instancia en su encabezado. Los métodos privados se pueden agregar a la extensión de clase sin restricciones, pero como notó Anomie, es técnicamente posible usarlos si sabes cómo se llaman, y con el volcado de clases, nada es seguro.

Ejemplo de uso de una extensión de clase:

@interface MyClass() 
@property (retain) id privateIvar; 
@property (readwrite) id readonlyProperty; // bonus! class extensions can be used to make a property that is publicly readonly and privately readwrite 
- (void)privateMethod; 
@end 
@implementation MyClass 
@synthesize privateIvar; // the runtime will create the actual ivar, and we just access it through the property 
- (void)privateMethod { 
    ... 
} 
... 

Otra forma de crear "variables de instancia" sin ponerlos en la cabecera o el uso de una propiedad es utilizar associative references, que añadir datos a un objeto en tiempo de ejecución. Técnicamente no son lo mismo que variables de instancia, y la sintaxis para ellos es más compleja. Como también requieren el nuevo tiempo de ejecución, solo hay dos razones por las que alguna vez querría usarlas: desea agregar una variable de instancia en una categoría (fuera del alcance de esta pregunta) o necesita que sea realmente privado. Una referencia asociativa no crea ningún método ni agrega a la definición de la clase en el código compilado, por lo que si no los crea envoltorios es imposible averiguarlos sin preguntar al objeto después de agregar los datos. Ver la parte inferior de la página que he vinculado para obtener un ejemplo completo de uso.

+0

Entonces ... si necesita un setter o getter personalizado para un ivar "oculto" de esta manera no puede escribir uno sin exponer el ivar en el encabezado? –

+0

@Martin: como dijo Bavarious, y como se discutió en los comentarios, los ivars ahora son compatibles con las extensiones de clase, por lo que puede declararlo allí en lugar del encabezado. También podría usar referencias asociativas y envoltorios de escritura a su alrededor como accesadores. – ughoavgfhw

Cuestiones relacionadas