¿Cómo declarar las variables de instancia y los methods no visibles o utilizables fuera de la instancia de class?

Revisé un montón de publicaciones sobre este tema. Tal vez no encontré "el uno" y alguien me señalará en esa dirección. La pregunta es simple y probablemente tenga una respuesta simple.

Si tiene dos Ivars, diga "public_ivar" y "private_ivar", ¿dónde / cómo debería declararlos para que lo público sea público y lo privado no esté expuesto de ninguna manera a cualquiera que vea el file de encabezado?

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

Me gustan los files de cabecera limpios (en otros idiomas) que solo exponen los methods y ivars que quiero que vea alguien más. Debe poder publicar su file de encabezado y no correr el riesgo de que alguien acceda a algo que se supone que no debe hacer. ¿Cómo se hace eso en el objective-C?

Por ejemplo, digamos que decido que necesito usar un ivar para realizar un seguimiento de algunos datos, un contador o algo así, entre varios methods de class que todos necesitan acceso a esta información. Si ese ivar se declara convencionalmente en el encabezado bajo @interface, su existencia se anuncia públicamente y es utilizable por cualquier persona que cree una instancia de la class. El escenario ideal sería que este ivar no fuera visible en absoluto fuera de la implementación de la class.

Puede declarar variables de instancia o properties declaradas en una extensión de class. Dado que se declara una extensión de class en un file de implementación (es decir, no un file de encabezado), no será visible para alguien que inspeccione el file de encabezado. Por ejemplo, en el file de encabezado:

@interface SomeClass : NSObject @end 

y en el file 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 count que no hay nada que impida el acceso a variables de instancia de extensión privada / class (o los methods de acceso para properties declaradas en una extensión de class) durante el time de ejecución. He escrito una publicación bastante detallada sobre esto como una respuesta a otra pregunta sobre Stack Overflow: ¿una privada @property crea una variable de instancia @private?

Editar: las variables de instancia en extensiones de class se presentaron en la session 144 de WWDC 2010.

Editar: "Usando el comstackdor Clang / LLVM 2.0, también puede declarar properties y variables de instancia en una extensión de class".

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

Use las extensiones de class para agregarlas a una class en su file de implementación. Una extensión de class es básicamente una categoría sin nombre con algunas bonificaciones: las properties declaradas en él se pueden sintetizar y cualquier cosa declarada debe estar en la implementación principal, por lo que el comstackdor puede verificar para asegurarse de que no se perdió una implementación. Debe poner la extensión de class antes de su implementación. No puede agregar variables de instancia directamente en una extensión de class, pero puede agregar properties. Cuando se sintetizan accesores para properties que no tienen variables de instancia correspondientes, el nuevo time de ejecución (os x 10.5 y posteriores y todas las versiones de iOS, creo) crearán automáticamente las variables de instancia. Esto significa que no puede crear sus propios accesores, sin embargo, a less que coloque la variable de instancia en su encabezado. Los methods privados se pueden agregar a la extensión de class sin restricciones, pero como Anomie señaló, técnicamente es posible usarlos si sabe a qué se llaman, y con el volcado de class, no hay nada seguro.

Ejemplo de uso de una extensión de class:

 @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 ponerlas en el encabezado o usar una propiedad es usar references asociativas , que agregan datos a un object en time de ejecución. Técnicamente, no son lo mismo que las variables de instancia, y la syntax para ellos es más compleja. Dado que también requieren el nuevo time de ejecución, solo hay dos razones por las cuales realmente querrías usarlas: quieres agregar una variable de instancia en una categoría (fuera del scope de esta pregunta) o necesitas que sea realmente realmente privada. Una reference asociativa no crea ningún método ni agrega a la definición de la class en el código comstackdo, por lo que si no crea contenedores para ellos es imposible averiguar acerca de ellos sin preguntar al object después de agregar los datos. Mira la parte inferior de la página que he enlazado para un ejemplo de uso completo.

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 file de encabezado, si alguien conoce el nombre y los arguments, puede llamarlo.