2012-01-12 8 views
20

¿Hay alguna razón para declarar un ivar privado en @interface en lugar de @implementation?Privado ivar en @interface o @implementation

veo código como este en todo el Internet (incluida la documentación proporcionada por Apple):

foo.h

@interface Foo : NSObject { 
@private 
    id _foo; 
} 
@end 

Foo.m

@implementation Foo 
// do something with _foo 
@end 

El El archivo de cabecera define la interfaz pública de una clase, mientras que un ivar privado es ... bien ... privado. Entonces, ¿por qué no declararlo así?

foo.h

@interface Foo : NSObject 
@end 

Foo.m

@implementation Foo { 
@private 
    id _foo; 
} 

// do something with _foo 
@end 

Respuesta

24

Declaración de variables de instancia en el @implementation es una característica reciente de Obj-C, es por eso que se ve mucho de código con ellos en el @interface - no había otra opción.

Si está utilizando un compilador que admita la declaración de variables de instancia en la implementación que los declara, probablemente exista el mejor valor predeterminado; solo colóquelos en la interfaz si es necesario que otros accedan a ellos.

Editar: Información adicional

Las variables de instancia declaradas en la aplicación son implícitamente oculta (efectivamente privado) y la visibilidad no se puede cambiar - @public, @protected y @private no producen errores de compilación (con el Clang actual al menos) pero son ignorados.

+1

En concreto, el compilador en cuestión parece ser Clang> 2. (Existente) GCC no lo hará. –

+0

En este contexto, 'Clang' es lo mismo que 'LLVM', ¿verdad? –

+0

@ranReloaded - no. Hay gcc - gcc front & backend, gcc-llvm - gcc frontend, llvm backend - y clang - clang frontend, llvm backend. Solo probé el clang, Josh probó en uno de los gcc. YMMV, solo inténtalo con el compilador que estés usando y mira. – CRD

4

Preferirías @interface si necesitas compatibilidad con el compilador para sistemas más antiguos o versiones de Xcode.

Si está seguro de que no necesitará esa compatibilidad hacia atrás, diría que es mejor colocarlo en el @implementation.

  • Creo que @private es un buen valor predeterminado.
  • Minimiza los tiempos de compilación y reduce las dependencias si lo usa correctamente.
  • Puede reducir gran parte de ese ruido en la parte superior de su encabezado. Muchas personas pondrán #imports para sus ivars, pero deberían usar una declaración forward como predeterminada. Por lo tanto, puede eliminar muchas #importaciones y muchas declaraciones directas de su encabezado.
3

Las directivas @ pública, @protected y @private son no comprometen de Objective-C, que son compilador pistas sobre la accesibilidad de las variables. NO LE RESTRINGE a usted de acceder a ellos.

ejemplo:

@interface Example : Object 
{ 
@public 
int x; 
@private 
int y; 
} 
... 


... 
id ex = [[Example alloc ] init]; 
ex->x = 10; 
ex->y = -10; 
printf(" x = %d , y = %d \n", ex->x , ex->y); 
... 

El compilador gcc escupe:

Main.m: 56: 1: advertencia: instance variable ‘y’ es @private; esto será un error difícil en el futuro

Main.m: 57: 1: advertencia: la variable de instancia 'y' es @private; este será un error de hardware en el futuro

una vez para cada acceso "innapropriate" a "privado" miembro y, pero compila todos modos.

Cuando se ejecuta se obtiene

x = 10 , y = -10 

Así que realmente depende de usted no escribir código de acceso de esta manera, sino porque objc es un superconjunto de C, sintaxis de C funciona muy bien, y todo las clases son transparentes.

Puede configurar el compilador para tratar estas advertencias como errores y fianza, pero el objetivo-C no está configurado internamente para este tipo de rigor. El envío de métodos dinámicos debería verificar el alcance y el permiso de cada llamada (slooooowwwww ...), por lo que, más allá de una advertencia en tiempo de compilación, el sistema espera que el programador respete el alcance de los miembros de datos.

Existen varios trucos para obtener la privacidad de los miembros en el objetivo-C. Una es asegurarse de poner la interfaz y las implementaciones de su clase en archivos .h y .m separados, respectivamente, y poner los miembros de datos en el archivo de implementación (el archivo .m). Entonces los archivos que importan los encabezados no tienen acceso a los miembros de datos, solo la clase en sí. A continuación, proporcione los métodos de acceso (o no) en el encabezado. Puede implementar las funciones setter/getter en el archivo de implementación para fines de diagnóstico si lo desea y serán habilitadas, , pero el acceso directo a los miembros de los datos no se realizará.

ejemplo:

@implementation Example2 :Object 
{ 
//nothing here 
} 
double hidden_d; // hey now this isn't seen by other files. 
id classdata; // neither is this. 

-(id) classdata { return [classdata data]; } // public accessor 
-(void) method2 { ... } 
@end 

// this is an "informal category" with no @interface section 
// these methods are not "published" in the header but are valid for the class 

@implementation Example2 (private) 
-(void)set_hidden_d:(double)d { hidden_d = d; } 

// You can only return by reference, not value, and the runtime sees (id) outside this file. 
// You must cast to (double*) and de-reference it to use it outside of this file. 
-(id) hidden_d_ptr { return &hidden_d;} 
@end 

... 
[Main.m] 
... 
ex2 = [[Example2 alloc] init]; 

double d = ex2->hidden_d; // error: 'struct Example2’ has no member named ‘hidden_d’ 
id data = ex2->classdata; // error: 'struct Example2’ has no member named ‘classdata’ 
id data = [ex2 classdata] // OK 

[ex2 set_hidden_d : 6.28318 ]; // warning:'Example2' may not respond to '-set_hidden_d:' 

double* dp = [ex2 hidden_d_ptr]; // (SO UGLY) warning: initialization from incompatible pointer type 
           // use (double*)cast -- <pointer-to-pointer conversion> 
double d = (*dp); // dereference pointer (also UGLY). 

... 

El compilador emitirá advertencias para tales chanchullos flagrantes, pero seguirá adelante y la confianza que usted sabe lo que está haciendo, y que tiene sus razones (ver (en realidad?) ¿tú?). ¿Parece mucho trabajo? ¿Propenso a errores? ¡Yay Baby! Intente refactorizar su código primero antes de recurrir a los trucos mágicos de C y la cirugía de albóndigas como esta.

Pero ahí está. Buena suerte.

+0

Me mantendría alejado de 'doble' en iOS;) –

Cuestiones relacionadas