2011-09-01 26 views

Respuesta

0

es una convención para mantener el ivar (variables de instancia) seguro, por lo que solo se puede acceder a través de getter y setter.

+2

Una mejor convención es no utilizar la sintaxis de puntos. – jer

+4

@synthesize es (y las propiedades en general son) sintaxis totalmente ortogonal a punto. –

1

He aquí por qué hago esto a veces:

Si yo quiero hacer la carga diferida en una propiedad típicamente Voy a subrayar mi Ivar por lo que el trabajo realizado para cargar los datos deseados desde el servidor back-end/guardados file/what-have-you solo se carga la primera vez. Por ejemplo:

- (NSMutableArray *)recentHistory; 
{ 
    if (_recentHistory == nil) 
    { 
     // Get it and set it, otherwise no work is needed... hooray! 
    } 

    return _recentHistory; 
} 

Así que aquí llama a la propiedad [instanceOfClass recentHistory] (o instanceOfClass.recentHistory) comprobará el Ivar para ver si se necesita para cargar los datos o simplemente devolver los datos ya cargados.

Es excesivo declarar todas sus propiedades de esta manera.

Espero que ayude.

+2

¿Pero realmente tiene que usar un guión bajo para esto o quiere decir simplemente como una convención? simplemente podría tener '@synthesize recentHistory;' y usar la variable de instancia 'recentHistory' o' self-> recentHistory' dentro del método 'recentHistory', solo asegúrese de no utilizar el nombre de propiedad' self.recentHistory' o '[self recentHistory] 'y causar una recursión. –

+0

no no, como una convención. Es una convención que también encontrarás en el código de Apple, que es probablemente la razón por la que la gente lo usa. La idea de tener un iVar y una propiedad a veces se usa en exceso, pero este es un caso en el que creo que se produce desde entonces. –

3

A veces es útil ver qué sucede detrás de las escenas para comprender. Básicamente cuando vea este

@property (nonatomic, retain) Foo *foo; 

Con esto en la puesta en práctica

@synthesize foo=_foo; 

Es el azúcar sintaxis para el siguiente, lo que significa que el compilador básicamente genera el código para usted

Foo *foo = nil; 

-(Foo *) foo { 
    return _foo; 
} 

-(void) setFoo:(Foo *)val { 
    if(_foo != val) { 
     [_foo release]; 
     _foo = [val retain]; 
    } 
} 

esta manera cuando se refiere a la propiedad pública, la golpea a través de los accesorios generados en self.foo y si desea consultar el variable de instancia dentro de su clase puede consultar _foo. Antes de XCode cuatro, era fácil confundirse entre los dos. Podría hacer algo como

self.foo = foo1; 

foo = foo2; 

Esto era perfectamente legal y podría causar problemas en un par de niveles. La segunda línea no usa el acceso, por lo que no se conservará foo2, lo que podría ocasionar que la recolección de basura la recoja prematuramente. Peor aún, la segunda línea no utiliza el acceso que liberaría ningún valor anterior, lo que significa que podría causar una pérdida de memoria.

Por lo tanto, en resumen, la nueva técnica crea un getter y un setter para su propiedad y le permite especificar también el nombre que se utilizará para la variable de instancia, utilizada para la encapsulación.

+0

Buena explicación. Solo pensar: 'if (_foo! = Nil) [_foo release];' el compilador no está generando una prueba vs nil, lo cual sería inútil, probaría si el nuevo valor es diferente del valor anterior. Consulte http://stackoverflow.com/questions/3924463/how-is-retain-setter-implemented-with-synthesize/3925204#3925204 para ver un ejemplo. – jv42

+0

Intenta ejecutar tu código con 'Foo * tmp = [Foo foo]; self.foo = tmp; self.foo = tmp; 'para verlo ir boom. – jv42

+0

Me salteó esa respuesta en mi iPad, no estaba 100% seguro de la implementación exacta, pero quería resaltar realmente el hecho de que maneja la administración de la memoria por usted y ayuda a evitar colisiones. ¡Gracias por el aviso! – jerrylroberts

1

solo quería agregar mis pensamientos a todas las respuestas anteriores.

en mi caso, lo uso principalmente para mantener mis clases a salvo de accidentes.

en mis archivos .h, declaro solo las propiedades sin ivars. en el archivo .m, utilizo el patrón @synthesize anterior para ocultar el ivar real de los usuarios, incluyéndome a mí, forzado a usar los accesadores sintetizados/dinámicos y no los ivars directamente. podría usar cualquier cosa para su nombre y no solo subrayarlo. p.ej.usted podría hacer:

@synthesize foo = _mySecretFoo; 
@synthesize bar = oneUglyVarBecauseIHateMyBoss; 

esta manera, su jefe sólo se vería bar, y que le resultará mucho más fácil, más seguro y por lo tanto, utilizar el descriptor de acceso de barras - si se utiliza la notación o mensajes de puntos.

prefiero este enfoque sobre el otro,

@property (getter=foo, setter=setFoo, ...) _mySecretFoo; 
@property (getter=bar, setter=setBar, ...) oneUglyVarBecauseIHateMyBoss; 

ya que esto no hace cumplir implementación privada y la encapsulación, y es simplemente escribiendo extra cuando Xcode puede hacer lo mismo para usted. Una cosa para recordar, ¡las propiedades no son lo mismo que ivars! podrías tener más propiedades que ivars, o al revés.

+0

Si he leído bien, lo hace sin declarar ivars explícitamente en un bloque '@implementation {...}'. ¿Cuál es la ventaja de usar '@synthesize bar = oneUgly;' si nunca puede referirse a 'oneUgly'? ¿Por qué no simplemente hacer '@synthesize bar;'? ¿Es porque tu camino da errores si escribes, por ejemplo, 'bar = 123.0'? –

+0

te refieres a declarar ivars en un bloque @interface {}. sí, obtendría un error si usa bar = 123, pero no es por eso que usaría el patrón anterior. este patrón es una conveniencia que permite exponer una interfaz pública mientras oculta totalmente su implementación, como este ejemplo de los documentos apple: '@syntheize age = numberOfYears;' también me permite hacer: 'SomeAccount * account = [SomeAccount defaultAccount ]; self.account = account; 'sin preocuparse por los errores, porque este es mi estilo de escritura de código. es puramente conveniente y estilo de codificación. –

Cuestiones relacionadas