objective-c - poner - guion bajo y arroba
¿Por qué renombrar propiedades sintetizadas en iOS con guiones bajos destacados? (4)
en la aplicación didFinishLaunchingWithOptions: método a la que se refieren la ventana y viewController ivars usando self
No, no lo son. Esas son referencias a la window
propiedades y viewController
. Ese es el punto del guión bajo, para que quede más claro cuando se usa la propiedad (sin guiones bajos) y cuando se está accediendo directamente al ivar (con guión bajo).
Posible duplicado:
¿Cómo funciona un guión bajo al frente de una variable en una clase de cacao objetivo-c?
Al crear un nuevo proyecto en Xcode 4, el código repetitivo agrega un carácter de subrayado cuando sintetiza los ivars en el archivo de implementación como:
@synthesize window = _window;
o:
@synthesize managedObjectContext = __managedObjectContext;
¿Puede alguien decirme qué se está logrando aquí? No soy una nube completa, pero este es un aspecto del objetivo-C No entiendo.
Otro punto de confusión; en la implementación del delegado de la aplicación, después de sintetizar la ventana iVar como se indica más arriba, en la aplicación didFinishLaunchingWithOptions: método se hace referencia a la ventana y viewController usando el valor self:
self.window.rootViewController = self.viewController
[self.window makeKeyAndVisible];
pero en el método dealloc es _window, o _viewController
Gracias
Aquí hay otra razón. Sin subrayar las variables de instancia, con frecuencia obtiene una advertencia con los parámetros self.title = title
y self.rating = rating
:
@implementation ScaryBugData
@synthesize title;
@synthesize rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // Warning. Local declaration hides instance variable
self.rating = rating; // Warning. Local declaration hides instance variable
}
return self;
}
@end
Evita la advertencia subrayando variables de instancia:
@implementation ScaryBugData
@synthesize title = _title;
@synthesize rating = _rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // No warning
self.rating = rating; // No warning
}
return self;
}
@end
Esto es un artefacto de una versión anterior del tiempo de ejecución de Objective-C.
Originalmente, @synthesize
se usaba para crear métodos de acceso, pero el tiempo de ejecución aún requería que las variables de instancia tuvieran que crearse instancias explícitamente:
@interface Foo : Bar {
Baz *_qux;
}
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
Las personas prefijarían sus variables de instancia para diferenciarlas de sus propiedades (aunque Apple no quiere que use guiones bajos, pero esa es una cuestión diferente). Sintetizas la propiedad para apuntar a la variable de instancia. Pero el punto es que _qux
es una variable de instancia y self.qux
(o [self qux]
) es el mensaje qux
enviado al objeto self
.
Usamos la variable de instancia directamente en -dealloc
; usar el método de acceso en su lugar sería así (aunque no lo recomiendo, por razones que explicaré en breve):
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
Esto tiene el efecto de liberar qux
, así como poner a cero la referencia. Pero esto puede tener efectos secundarios desafortunados:
- Puede terminar disparando algunas notificaciones inesperadas. Otros objetos pueden estar observando cambios en
qux
, que se registran cuando se utiliza un método de acceso para cambiarlo. - (No todo el mundo está de acuerdo en este punto :) Al poner en cero el puntero como lo hace el descriptor, es posible que se oculten errores de lógica en el programa. Si alguna vez tiene acceso a una variable de instancia de un objeto después de que el objeto ha sido desasignado, está cometiendo un error grave. Sin embargo, debido a la semántica de mensajes
nil
de Objective-C, nunca lo sabrás, ya que usaste el acceso para establecerlo ennil
. Si hubiera liberado la variable de instancia directamente y no hubiera puesto a cero la referencia, el acceso al objeto desasignado hubiera causado unEXC_BAD_ACCESS
fuerte.
Las versiones posteriores del tiempo de ejecución agregaron la capacidad de sintetizar variables de instancia además de los métodos de acceso. Con estas versiones del tiempo de ejecución, el código anterior se puede escribir omitiendo las variables de instancia:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
Esto realmente sintetiza una variable de instancia en Foo
llamada _qux
, a la que acceden los mensajes getter y setter -qux
y -setQux:
Recomiendo esto: es un poco desordenado, pero hay una buena razón para usar el guión bajo; a saber, para proteger contra el acceso directo accidental de ivar. Si crees que puedes confiar en ti mismo para recordar si estás usando una variable de instancia sin formato o un método de acceso, simplemente hazlo de esta manera:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux;
- (void)dealloc {
[qux release];
[super dealloc];
}
@end
Luego, cuando quiera acceder directamente a la variable de instancia, simplemente diga qux
(que se traduce en self->qux
en sintaxis C para acceder a un miembro desde un puntero). Cuando desee usar métodos de acceso (que notificarán a los observadores, y harán otras cosas interesantes, y harán las cosas más seguras y fáciles con respecto a la administración de la memoria), use self.qux
( [self qux]
) y self.qux = blah;
( [self setQux:blah]
).
Lo triste aquí es que el código de muestra y el código de plantilla de Apple apestan. Nunca lo use como una guía para el estilo Objective-C apropiado, y ciertamente nunca lo use como una guía para una arquitectura de software adecuada. :)
Sí, es solo para diferenciar la referencia del objeto. Es decir, si el objeto se refiere directamente, úselo con guión bajo; de lo contrario, use self para referir el objeto.