2009-02-14 13 views
15

¿Qué convenciones siguen las personas aquí para nombrar variables de instancia y argumentos de método, particularmente cuando los argumentos de método se usan para establecer ivars (variables de instancia)?variable de instancia/método asignación de argumentos en Objectivo C

En C++ solía usar el prefijo m_ para ivars mucho. En C#, seguí la convención de desambiguación puramente mediante el uso de this. para ivars. Desde entonces adopté el equivalente en C++ también (this->).

En Objective C He intentado algunas cosas pero ninguna me ha parecido realmente satisfactoria.

A menos que alguien sugiera algo realmente agradable, me resigno al hecho de que tendré que comprometerme (pero, por favor, ¡no me hagas usar el prefijo the para args!), Así que estoy interesado en saber qué la mayoría dice, especialmente de aquellos que han estado usando ObjC por un tiempo.

he hecho un poco de diligencia debida antes de publicar esto y un par de buenos recursos que encontré donde:

Me dan algunas ideas, pero todavía estoy ansioso por escuchar lo que otros están haciendo.

[editar] Solo para aclarar: Es específicamente cómo distinguir Ivars de argumentos del método que estoy buscando - ya sea a través de prefijos o alguna otra técnica.

[editar 2] Gracias por todas las respuestas y puntos de discusión. No estoy cerrando esto, pero solo diré que, como indiqué en mis comentarios a la respuesta aceptada, me he ido con la convención de anteponer init args con the (y setter args con new, lo cual estaba haciendo de todos modos) . Este parece ser el mejor equilibrio de fuerzas, incluso si yo mismo no estoy interesado en la estética.

Respuesta

17

Como habrás notado, el estilo Cocoa es usar nombres de argumento de método como theValue si el nombre del argumento entrará en conflicto con una variable de instancia. Sin embargo, no debería haber muchas veces que esto aparezca en el código de estilo Objective-C 2.0. La suposición es que no debería (normalmente) acceder a las variables de instancia directamente. Principalmente esto se debe a que al hacerlo se evita la maquinaria de Observación de valores-clave en Cocoa. Por el contrario, la expectativa es que acceda y mute las propiedades a través de métodos getter/setter. En Objective-C 2.0, es fácil declarar estas propiedades y automáticamente @synthesize los getters/setters, por lo que no hay muchas excusas para no usarlos. De hecho, en sistemas de 64 bits, el tiempo de ejecución creará automáticamente las variables de instancia para usted, obviando la necesidad de declararlas y reduciendo la necesidad de usarlas.

La única vez que usted debe estar accediendo a las variables de instancia directamente en -init y -dealloc métodos:

@interface MyObject : NSObject 
{ 
    id ivar; 
} 

@property (retain,readwrite) id ivar; //or whatever retain/copy/assign and read/readwrite makes sense 
@end 

@implementation MyObject 
@synthesize ivar; 

- (id)initWithIvar:(id)theIvar { 
    if(self = [super init]) { 
    ivar = theIvar; 
    } 

    return self; 
} 

- (void)dealloc { 
    [ivar release]; 
} 

La razón por la Ivar debe utilizarse directamente en estos casos es por culpa del captador/definidor pueden tener efectos secundarios que Depende de una instancia completamente inicializada, lo que los hace peligrosos en -init y -dealloc donde el estado del objeto está completamente inicializado.En todos los demás casos, debe usar self.ivar (o [self ivar] y [self setIvar:newValue]).

Parece que los métodos distintos de -initWithXX no deberían tener el conflicto de nomenclatura. Si lo hacen, ¿no deberían refactorizarse para no tener ese parámetro o para que la Clase no tenga la variable de instancia?

Esto deja solo los métodos -initWithXX donde a menudo encontrará un conflicto entre argumentos y ivars. Para este caso, puede usar cualquiera de los enfoques que menciona si realmente no puede soportar el estilo Cocoa. Prefijo con _ funciona y es relativamente común (creo que los ajustadores y captadores @synthesize 'd harán automáticamente lo correcto en este caso, pero es posible que deba establecer explícitamente _ivar como respaldo).

+2

Gracias Barry. El problema con el uso de los adaptadores dentro de la implementación de la clase es que agregan una sobrecarga significativa, que puede ignorar en las aplicaciones de escritorio, pero en el iPhone pueden sumarse. Además, como dices, pueden tener efectos secundarios que no desees desde el impl ... – philsquared

+1

... [cont]. Dicho esto, es principalmente en los métodos init que se produce el choque (en los mutadores usualmente uso newX o similar de todos modos). Como el consenso parece estar en el o como un prefijo para los argumentos, quizás pueda vivir con eso solo dentro de los métodos init. Eso mantiene a los ivars más limpios. – philsquared

+1

Verificaría que el acceso a la propiedad frente al acceso directo a ivar es un golpe de rendimiento inaceptable. Aclaré anteriormente por qué tienes que acceder a ivar directamente en init/dealloc. De lo contrario, parece peligroso tener acceso directo al lado del acceso a la propiedad, ya que enturbia la semántica del estado ivar. –

2

Así es como Apple does it.

+0

Gracias wfarr. Sin embargo, eso en realidad no describe una convención de nomenclatura para ivars o argumentos de método (aparte de decir, "Asegúrese de que el nombre de la variable de instancia describa concisamente el atributo almacenado.") – philsquared

+0

Su edición aclaró las cosas. Creo que he visto gente que usa _ como un prefijo para diferenciar ivars de los métodos args. – wfarr

+0

el problema con _ como prefijo es que está reservado por Apple, y lo usan en una serie de clases base (información sobre eso en algunos de los enlaces que proporcioné). – philsquared

1

El código de ejemplo producido por Apple generalmente usa un prefijo "_". Creo que también vi algunos usando mFoo o m_foo. Algunos no se molestan con los prefijos y simplemente usan un nombre normal, sin embargo, eso se vuelve confuso más adelante. En general, cuando se definen los parámetros del método, la convención de nomenclatura es usar un prefijo "a", "an", "the" o "new". Por ejemplo:

@interface Foo : NSObject { 
    id _bar; 
} 
@property (nonatomic, retain) id bar; 

- (id) initWithBar:(id)aBar; 

@end 

@implementation Foo 
@synthesize bar = _bar; 

- (id) initWithBar:(id)aBar { 
    self = [super init]; 
    if(self != nil) { 
     _bar = aBar; 
    } 
    return self; 
} 

@end 

Me parece que esta convención funciona bastante bien. Solía ​​no molestarme con el prefijo, pero eso hacía que las cosas fueran confusas a veces. Usar un prefijo indica claramente que es una variable de instancia. La convención @synthesize bar = _bar es utilizada por Apple en su código de ejemplo (iPhone).

La variable de instancia normalmente no se usaría de todos modos, por lo que si considera que el prefijo "_" es molesto, no importa, porque usaría [self bar] (o self.bar si le gusta ese tipo de cosas) de todos modos .

+1

Gracias sebnow. Apple reserva el prefijo de subrayado para evitar conflictos de nombres (ver: http://developer.apple.com/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingBasics.html#//apple_ref/doc/uid/20001281 - y el fin de "Convenciones tipográficas"). Prefiero evitarlo – philsquared

+0

No sabía de eso. Buena atrapada. – sebnow

+3

Apple * no * reserva el prefijo de subrayado para los nombres de variable de instancia. Solo para nombres de métodos. –

2

Para completar todos los styleGuides de Objective-C conocidos here es la versión de google. Lo que hacen es agregar un guión bajo después del miembro varname. Por ejemplo, BOOL isActive_;.
Así que haga una elección y quédese con ella. También prefiero el prefijo "_" para mis aplicaciones.

1

Obj-C no define "estilo" tan estrictamente como en muchos otros idiomas, esto podría ser algo bueno o más bien malo, pero significa que está solo para encontrar un buen estilo de codificación la mayor parte del tiempo .

También puede acceder a las variables en Obj-C a través de uno mismo. Entonces, si tienes una prueba de variable de instancia, puedes acceder a ella a través de auto-> prueba, esto es legítimo y siempre funcionará. Sin embargo, a los ojos de la mayoría de los programadores Obj-C no es bello. Revela el "secreto", que los objetos son, en realidad, simples estructuras (más precisamente, los objetos refs son punteros a estructuras) y los vars de instancia son, de hecho, miembros estructurales. No es que esto sea realmente secreto, pero los programadores de Obj-C parecen preferir "ocultar" este hecho en su código.

Usar guión bajo "_" en el nombre es una muy mala idea. Alguien aquí señaló que Apple reserva un guión bajo para su código, pero en realidad, GCC ya reserva un guión bajo para los nombres de los símbolos. Más precisamente, ya el estándar ANSI-C dice que las variables que comienzan con dos guiones bajos o un guión bajo y una letra mayúscula se reservan para el uso interno del compilador. Entonces, usar un guión bajo es en teoría válido, pero accidentalmente comienza el nombre con una letra mayúscula y se vuelve inválido.

Lo que intenté hasta ahora fue usar el prefijo my, myName en lugar del nombre, y usar el prefijo self, selfName en lugar del nombre; parece algo extraño al principio, pero no se ve tan mal en un gran fragmento de código. Al menos inmediatamente llama la atención por ser "diferente".También probé una sola "i", iName en lugar de nombre (o iname en lugar de nombre), pero no estaba muy satisfecho con esa solución.

Sin embargo, nunca perdí el tiempo pensando en los parámetros del método. Porque realmente no importa. Esas son variables como cualquier otra variable, a menos que se declaren constantes. Incluso pueden ser reutilizados para otros fines dentro del método, ya que no afectarán a la persona que llama. P.ej.

- (NSImage *)loadImage:(int)imageNumber 
{ 
    NSImage * res; 

    // Some code that assigns a value to res 
    // ... 

    // Re-use imageNumber for a different purpose 
    for (imageNumber = 0; ...; ...) { 
    // Some code 
    } 

    return res; 
} 

No veo ningún problema con ese código. ¿Por qué tendría que declarar una segunda variable de pila para eso, siempre y cuando el nombre aún tenga sentido (si no estoy iterando sobre las imágenes por número en el ciclo for, el nombre no tiene sentido, por supuesto, en ese caso usaría una variable diferente para él - el compilador de hecho puede reservar solo una int en la pila para ambos).

Cuestiones relacionadas