2011-03-29 9 views
126

Duplicar posible:
How does an underscore in front of a variable in a cocoa objective-c class work?¿Por qué cambiar el nombre de las propiedades sintetizadas en iOS con guiones bajos destacados?

Al crear un nuevo proyecto en Xcode 4, el código repetitivo añade un carácter de subrayado cuando se sintetiza las 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 de aplicaciones delegado, después de sintetizar el Ivar ventana, como anteriormente, en los didFinishLaunchingWithOptions de aplicación: Método de la ventana y ivars ViewController se hace referencia a la utilización de uno mismo:

self.window.rootViewController = self.viewController 
[self.window makeKeyAndVisible]; 

pero en el método dealloc es _window o _viewController

Gracias

Respuesta

223

Esto es un artefacto de una versión anterior del tiempo de ejecución de Objective-C.

Originalmente, @synthesize se utilizó para crear métodos descriptores de acceso, pero el tiempo de ejecución sigue siendo necesario que las variables de instancia tuvieron que crear una instancia explícita:

@interface Foo : Bar { 
    Baz *_qux; 
} 

@property (retain) Baz *qux; 
@end 

@implementation Foo 
@synthesize qux = _qux; 

- (void)dealloc { 
    [_qux release]; 
    [super dealloc]; 
} 

@end 

La gente prefijo sus variables de instancia para diferenciarlos de sus propiedades (aunque Apple no quiere que uses 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; utilizando el método de acceso en su lugar sería el siguiente (aunque yo 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 poniendo 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 con este punto :) Al poner en cero el puntero como lo hace el descriptor puede ocultar errores de lógica en su programa. Si alguna vez tiene acceso a una variable de instancia de un objeto después de el objeto ha sido desasignado, está cometiendo un error grave. Sin embargo, debido a la semántica de los mensajes de nil de Objective-C, nunca lo sabrás, habiendo usado el acceso para establecerlo en nil. Si hubiera liberado la variable de instancia directamente y no hubiera puesto a cero la referencia, el acceso al objeto desasignado hubiera causado un fuerte EXC_BAD_ACCESS.

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 

En realidad, esto sintetiza una variable de instancia en Foo llamado _qux, al que se accede por getter y mensajes 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 usted cree que puede confiar en ti mismo para recordar si usted está utilizando una variable de instancia crudo o al método de acceso, simplemente hacerlo de esta manera en su lugar:

@interface Foo : Bar 
@property (retain) Baz *qux; 
@end 

@implementation Foo 
@synthesize qux; 

- (void)dealloc { 
    [qux release]; 
    [super dealloc]; 
} 

@end 

Entonces, cuando se quiere acceder a la variable de instancia en forma directa, diga qux (que se traduce en self->qux en sintaxis C para acceder a un miembro desde un puntero). Cuando desee utilizar 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 memoria), use self.qux ([self qux]) y self.qux = blah; ([self setQux:blah]).

Lo triste aquí es que el código de ejemplo y código de plantilla de Apple apesta. 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. :)

+59

hay una muy buena razón para '@synthesize QUZ = _quz; '; elimina accidentalmente escribir 'quz' cuando te refieres a' self.quz' y viceversa. El problema del compilador fue relativamente efímero, pero real. Si encuentra ejemplos borked, por favor presente errores. – bbum

+1

@bbum Buen punto para subrayar-nombrar.Por lo general, confío en mí mismo para escribir lo correcto (o al menos corregirlo si me equivoco), pero definitivamente es algo en lo que pensar al diseñar su estilo de codificación (tiendo a equivocarme por el lado de la estética, pero es perfectamente válido para inclinarse hacia la protección contra accidentes). –

+0

Si no desea escribir todo el modelo a mano, puede usar https://github.com/holtwick/xobjc (autopromoción desvergonzado de un proyecto de código abierto;)) Es compatible con los caracteres de subrayado iniciales y finales. . Los siguientes son recomendados por Google Styleguide para ObjC. Esto también es útil, porque Apple también usa guiones bajos en su propio código, por lo que puede tener problemas con la API privada en casos excepcionales. – Holtwick

6

en los didFinishLaunchingWithOptions APLICACION: Forma de la ventana y Ivars ViewController se hace referencia a la utilización de uno mismo

No, no lo son. Esas son referencias a las propiedades window 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).

2

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.

13

Aquí hay otra razón. Sin subrayando las variables de instancia se obtienen con frecuencia 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 

a evitar la advertencia subrayando las 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 
+0

Me encanta el código de muestra de [los fantásticos tutoriales de la aplicación Scary Bugs de Ray Wenderlich] (http://www.raywenderlich.com/1797/ios-tutorial-how-to-create-a-simple-iphone-app-part-1) :) – nicksuch

Cuestiones relacionadas