Pregunta

Decir que tengo lo siguiente:

@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

A 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 - por suerte - esta asignación actúa como era de esperar, y el I set 'foobar' to 'BAZ!' código imprime. Por desgracia, esto se siente como una contradicción, ya que el valor de retorno del colocador Se invoca oculta el hecho de que la asignación devuelve el valor asignado a la misma. Al principio pensé que mcInst.foobar = @"BAZ!"; está haciendo dos llamadas en su lugar un bloque: en primer lugar el setter y getter para reunir el valor de retorno. Sin embargo, la instrumentación de los métodos setter y getter con llamadas NSLog demuestra este no es el caso.

¿Fue útil?

Solución

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 detalles están disponibles abajo, pero podría ayudar a considerar la siguiente modificación en el método de setFoobar:

- (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 se está estableciendo, pero su línea de código seguirá mostrando el valor 'BAZ!' .

Detalles de:

Como se ha señalado por 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 se encarga de este comportamiento mediante el uso de una variable temporal (*). En esencia, lo que pasa detrás de las escenas es como la siguiente:

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

En el mismo sentido, se puede hacer lo siguiente:

SomeFunction(x = 42);

esta línea de código se copia el valor de x en 42 y, a continuación, 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);

(*) señalan 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.

Otros consejos

No hay necesidad de llamar a un captador - tiene el valor que se le asigna allí mismo, en la misma línea. Se puede pensar en ella como la ampliación a [mcInst setFoobar:@"BAZ!"], @"BAZ!".

en C, misiones es una expresión, que se evalúa como el valor asignado

Esto es debido 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 que tiene sentido para mí que a pesar de que la asignación funciona llamando a un método en el comportamiento mcInst lo mismo que con C. El valor de la expresión de asignación es el operando de la izquierda después de la asignación (@"BAZ!") por lo que este valor se pasa a la NSLog función.

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

P.S. Es una buena pregunta para preguntar por qué el compilador llame el organismo en la propiedad cuando se asigna el valor a ella y no llamar al comprador cuando se utiliza el valor de mcInst.foobar después. Yo diría que es simplemente asumió el comprador devolverá el mismo valor que se acaba de asignar a la propiedad y por lo tanto el comprador no se llama.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top