6

Decir que tengo el siguiente:La asignación de propiedad Objective-C devuelve el valor asignado?

@interface MyClass : NSObject { NSString* _foobar; } 
@property (nonatomic, retain) NSString* foobar; 
@end 

@implementation MyClass 
@dynamic foobar; 
- (void) setFoobar:(NSString*)fbSet; { [_foobar release]; _foobar = [fbSet retain]; } 
- (NSString*) foobar; { return _foobar; } 
@end 

continuación:

MyClass* mcInst = [[[MyClass alloc] init] autorelease]; 
NSLog(@"I set 'foobar' to '%@'", (mcInst.foobar = @"BAZ!")); 

Mirando el valor de retorno de -[MyClass setFoobar:], se podría suponer aquí que esta línea imprimiría I set 'foobar' to '', ya que la asignación parece devolver nada .

Sin embargo, afortunadamente, esta asignación funciona como se esperaba, y el código imprime I set 'foobar' to 'BAZ!'. Desafortunadamente, esto parece una contradicción, porque el valor de retorno del instalador invocado oculta el hecho de que la asignación devuelve el valor asignado. Al principio pensé que mcInst.foobar = @"BAZ!"; estaba haciendo dos llamadas en lugar de un bloque: primero el colocador y luego el captador para recopilar el valor de retorno. Sin embargo, la instrumentación de los métodos setter y getter con llamadas NSLog demuestra que este no es el caso.

+1

Creo que en lugar de "¿Por qué funciona NSLog?", Una mejor pregunta (y creo que la pregunta es) es "¿por qué el colocador devuelve vacío, y no (en este caso) NSString *? También había asumido que mcInst.foobar = era solo azúcar sintáctica para [mcInst setFoobar: ...] Supongo que no ... –

+1

Sí, la pregunta es por qué el compilador arroja un error cuando se usa 'NSLog (@" I set ' foobar 'a'% @ ', [mcInst setFoobar: @ "BAZ!"]);' reconociendo que el método no devuelve nada, pero te permite hacerlo de otra manera. – Dimitris

+0

Brian: sí, eso fue de hecho la pregunta que estaba tratando de preguntar, aunque mi redacción puede haber ocultado que =) – rpj

Respuesta

9

Resumen rápida:

La respuesta rápida es que no hay ninguna contradicción, ya que el resultado de la expresión:

(mcInst.foobar = @"BAZ!") 

es en realidad @"BAZ!", y no mcInst.foobar.

más detalle está disponible abajo, pero podría ayudar a considerar la siguiente modificación a su setFoobar método:

- (void) setFoobar:(NSString*)fbSet 
{ 
    [_foobar release]; 
    _foobar = [[NSString stringWithFormat:@"HELLO_%@", fbSet] retain]; 
} 

Con este código en su lugar, el valor de la propiedad foobar se modifica mientras que se está creando , pero su línea de código seguirá mostrando el valor 'BAZ!'.

Detalles:

como ha señalado newacct, su código NSLog funciona porque se utiliza el operador de asignación (=), que tiene un comportamiento muy específico en el lenguaje C (que Objective-C se basa en)

En C, puede hacer lo siguiente:

x = y = z = 42; 

y todas las variables, x, y y z contendrá el valor 42.

El compilador maneja este comportamiento utilizando una variable temporal (*).En esencia, lo que sucede detrás de las escenas se ve algo como esto:

tempVar = 42; 
z = tempVar; 
y = tempVar; 
x = tempVar; 

En la misma línea, puede hacer lo siguiente:

SomeFunction(x = 42); 

esta línea de código se copia el valor de 42 en x, y luego llamar SomeFunction con un argumento de 42. Detrás de las escenas, que se ve así:

tempVar = 42; 
x = tempVar; 
SomeFunction(tempVar); 

Ahora, en Objective-C, su línea de registro se maneja de la siguiente manera:

tempVar = @"BAZ!"; 
[mcInst setFooBar:tempVar]; 
NSLog(@"I set 'foobar' to '%@'", tempVar); 

(*) cuenta que el uso de una "variable temporaray" describo está destinado a ilustrar el concepto, y en realidad no puede reflejar lo que cualquier compilador dado realmente hace bajo el capó. Ese tipo de detalle de implementación depende de los programadores que escriben el compilador, y cada uno puede hacer algo diferente. El resultado final, sin embargo, es el mismo.

+0

Entiendo el comportamiento de C y cómo lo realiza el compilador. Supongo que su punto del compilador que usa una variable de temperatura tiene sentido, así que gracias. Sin embargo, el foco de mi pregunta fue sobre la aparente contradicción entre un método que devuelve vacío (que es en lo que se reduce la sintaxis de propiedad en Objective-C) y la asignación que devuelve el valor asignado. – rpj

+1

Hmm. Creo que pude haber enterrado el concepto clave debajo de demasiados detalles. Si echas un vistazo al último bloque de código en mi respuesta, puedes ver por qué el uso de una variable temporal hace que el valor de retorno del acceso a la propiedad sea irrelevante. El acceso directo a la propiedad simplemente se denomina como uno de los pasos para ejecutar su línea 'NSLog (...)', y es la variable temporal que pasa a 'NSLog'. –

+0

Puse el punto crítico en la parte superior de mi respuesta, y agregué otro ejemplo que podría ayudar a ilustrar. ¡Espero que ayude! –

0

en C, la asignación es una expresión, que se evalúa al valor asignado

+0

Lo entiendo, e incluso lo señalé. Estoy buscando los detalles de la implementación de Objective-C. – rpj

0

Esto se debe a la forma en que funciona el operador de asignación C. Como se describe en el estándar ANSI C:

"Un operador de asignación almacena un valor en el objeto designado por el operando de la izquierda una expresión de asignación tiene el valor de la izquierda operando después de la asignación ..."

Su expresión de asignación es mcInst.foobar = @"BAZ!". Parece tener sentido para mí que, aunque la asignación funcione llamando a un método en mcInst, el comportamiento sea el mismo que con C. El valor de la expresión de asignación es el operando izquierdo después de la asignación (@"BAZ!"), por lo que este valor se pasa al Función NSLog.

Este es el mismo comportamiento que le permite escribir un inicializador en el estilo de if (self = [super init]).

P.S. Es una pregunta justa preguntar por qué el compilador llama al colocador en la propiedad cuando le asigna el valor y no llama al getter cuando usa el valor de mcInst.foobar después. Diría que simplemente se supone que el getter devolverá el mismo valor que se acaba de asignar a la propiedad y, por lo tanto, no se llama al getter.

1

No hay necesidad de llamar a un getter: tiene el valor asignado allí en la misma línea. Puede pensar que se expande al [mcInst setFoobar:@"BAZ!"], @"BAZ!".

Cuestiones relacionadas