Pregunta sobre @synthesize

Cuando creas una nueva aplicación de Xcode que incorpora CoreData, tienes esas líneas en el archivo de implementación del delegado:

@synthesize window=_window; @synthesize managedObjectContext=__managedObjectContext; 

¿Cuáles son las diferencias entre usar solo un guión bajo o duplicarlo? ¿Cuál es la diferencia al escribir solo?

 @synthesize window; 

Un subrayado inicial es una convención de nomenclatura útil para diferenciar entre variables de instancia y accesadores. Para el comstackdor, es solo un cambio de nombre de ivar común.

Considere la diferencia (código no ARC):

 self.date = [NSDate date]; // OK, the setter releases the old value first date = [NSDate date]; // WRONG, skipping the setter causes a memory leak _date = [NSDate date]; // WRONG but easier to see it's not a local variable 

Con ARC, las variables no se filtrarán, pero sigue siendo incorrecto omitir los atributos @property:

 @property (copy) string; // ... self.string = someString; // OK, string is copied string = someString; // WRONG string is retained but not copied _string = someString; // WRONG but hopefully easier to see 

Lo que es peor, algunas API como Core Data confían en las notificaciones de KVC para realizar una carga diferida. Si salta accidentalmente los accesorios, sus datos volverán a ser nulos.

Esta es la razón por la que a menudo se encuentra @synthesize var=_var , lo que hace

  • self.var una referencia de acceso (invocando setters y getters),
  • _var una referencia de acceso directo (omitiendo setters y getters),
  • y var una referencia no válida.

Dado que @synthesize var=_var es autogenerado por LLVM 4.0 cuando se omite @synthesize , puede considerarlo como la convención de nomenclatura predeterminada en Objective-C.

Sigue leyendo para más detalles …


Tiempo de ejecución moderno

En Objective-C 2.0 declaras variables como esta:

 @interface User : NSObject @property (nonatomic, assign) NSInteger age; @end @implementation User { @synthesize age; // this line can be omitted since LLVM 4.0 @end 

que se traduce por el comstackdor de la siguiente manera:

 @interface User : NSObject { NSInteger age; } @end @implementation User -(void)setAge:(NSInteger)newAge { age=newAge; } -(void)age { return age; } @end 

Si prefiere usar la convención de subrayado solo agregue lo siguiente:

 @synthesize age=_age; 

Eso es todo lo que necesita porque con el tiempo de ejecución moderno , si no proporciona una variable de instancia, el comstackdor agrega uno para usted . Aquí está el código que se comstack:

 @interface User : NSObject { NSInteger _age; } @end @implementation User -(void)setAge:(NSInteger)newAge { _age=newAge; } -(void)age { return _age; } @end 

¿Qué sucede si agrega tanto el ivar como la propiedad @? Si la variable tiene el mismo nombre y tipo, el comstackdor la usa en su lugar generando una nueva variable. Citando el lenguaje de progtwigción Objective-C> Propiedades declaradas> Directivas de implementación de propiedad :

Existen diferencias en el comportamiento de la síntesis de acceso que dependen del tiempo de ejecución:

  • Para los tiempos de ejecución modernos, las variables de instancia se sintetizan según sea necesario. Si ya existe una variable de instancia del mismo nombre, se usa.

  • Para los tiempos de ejecución heredados, las variables de instancia ya deben declararse en el bloque @interface de la clase actual. Si existe una variable de instancia del mismo nombre que la propiedad, y si su tipo es compatible con el tipo de propiedad, se utiliza; de lo contrario, se obtiene un error de comstackción.

Tiempo de ejecución heredado

Pero si necesita admitir el tiempo de ejecución heredado , debe proporcionar una variable de instancia con el mismo nombre y tipo compatible de la propiedad o especificar otra variable de instancia existente en la instrucción @synthesize .

Entonces, el código heredado sin guiones bajos sería:

 @interface User : NSObject { NSInteger age; } @property (nonatomic, assign) NSInteger age; @end @implementation User @synthesize age; @end 

O si prefiere la convención de subrayado:

 @interface User : NSObject { NSInteger _age; } @property (nonatomic, assign) NSInteger age; @end @implementation User @synthesize age = _age; @end 

¿Cuál es la mejor manera?

Apple desaconseja el uso de guiones bajos en los métodos, ¡pero no en las variables !.

Apple en métodos: Pautas de encoding para el cocoa: Convenciones tipográficas :

Evite el uso del carácter de subrayado como un prefijo que significa privado, especialmente en los métodos. Apple se reserva el uso de esta convención. El uso por parte de terceros puede provocar colisiones entre nombres y espacios; podrían ignorar involuntariamente un método privado existente con uno propio, con consecuencias desastrosas.

Apple en las variables: propiedades declaradas y variables de instancia

Asegúrese de que el nombre de la variable de instancia describa concisamente el atributo almacenado. Por lo general, no debe acceder directamente a las variables de instancia, sino que debe usar métodos de acceso (se accede directamente a las variables de instancia en los métodos init y dealloc). Para ayudar a señalizar esto, prefija los nombres de las variables de instancia con un guión bajo (_) , por ejemplo: @implementation MyClass { BOOL _showsTitle; } @implementation MyClass { BOOL _showsTitle; }

ISO / IEC 9899 7.1.3 Identificadores reservados (también conocido como C99):

  • Todos los identificadores que comienzan con un guión bajo y una letra mayúscula u otro guión bajo siempre están reservados para cualquier uso.
  • Todos los identificadores que comienzan con un guión bajo siempre están reservados para su uso como identificadores con scope de archivo en los espacios de nombre ordinario y de nombre de etiqueta.

Además de eso, el guion bajo doble está tradicionalmente reservado para el proveedor del preprocesador / comstackdor / biblioteca. Esto evita el caso en el que utiliza __block en algún lugar de su código, y Apple lo introduce como una nueva palabra clave no estándar.

Guía de estilo de Google Objective-C :

Nombres de variables Los nombres de variables comienzan con minúsculas y usan mayúsculas y minúsculas para delimitar palabras. Las variables de los miembros de la clase tienen guiones bajos posteriores . Por ejemplo: myLocalVariable, myInstanceVariable_. Los miembros utilizados para enlaces KVO / KVC pueden comenzar con un guion bajo si no se permite el uso de @property de Objective-C 2.0.

El guión bajo final de Google no lo obliga a escribir un carácter más antes de que Xcode active el autocompletado, pero se dará cuenta de que es una variable de instancia más lenta si el subrayado es un sufijo.

El subrayado inicial también se desaconseja en C ++ (consulte ¿Cuáles son las reglas sobre el uso de un guión bajo en un identificador C ++? ) Y las propiedades de Datos centrales (intente agregar un subrayado inicial en el modelo y obtendrá “El nombre debe comenzar con una letra”) .

Lo que sea que elija, es poco probable que ocurran colisiones, y si lo hacen, recibirá una advertencia del comstackdor. En caso de duda, use la forma LLVM predeterminada: @synthesize var=_var;


Tengo una edición de esta publicación para leer A Motivation for ivar decorations de Mark Dalrymple. Es posible que desee comprobarlo.

Puedes usar solo

@synthesize window;

Sin embargo, si su variable de instancia se llama ‘ventana’, algunas personas usan una convención de nomenclatura de prefijar todas las variables de instancia con subrayado, pero aún prefieren tener sus getters y setters sin el prefijo de subrayado, eso es lo que significa ‘window = _window’.

No sé qué significa doble guión bajo, pero sospecho que también se trata de una convención de nomenclatura.