Domanda

Dire che ho il seguente:

@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

Quindi:

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

Guardando il valore di ritorno di -[MyClass setFoobar:], si potrebbe supporre che questa linea qui sarebbe stampare I set 'foobar' to '', perché l'assegnazione sembra di tornare nulla.

Tuttavia - per fortuna - questa assegnazione si comporta come previsto, e la stampa di codici a I set 'foobar' to 'BAZ!'. Purtroppo, questo si sente come una contraddizione, perché il valore di ritorno del palleggiatore Richiamato nasconde il fatto che l'assegnazione restituisce il valore assegnato ad esso. In un primo momento ho pensato che mcInst.foobar = @"BAZ!"; sta compiendo due chiamate invece un blocco: prima il setter e poi il getter per raccogliere il valore di ritorno. Tuttavia, la strumentazione i metodi setter e getter con chiamate NSLog dimostra questo non è il caso.

È stato utile?

Soluzione

Riepilogo rapida:

La risposta più immediata è che non v'è contraddizione, perché il risultato dell'espressione:

(mcInst.foobar = @"BAZ!")

è in realtà @"BAZ!", e non mcInst.foobar.

Maggiori dettagli sono disponibili sotto, ma potrebbe aiutare a prendere in considerazione la seguente modifica al metodo di setFoobar:

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

Con questo codice in atto, il valore della proprietà foobar viene modificata mentre viene impostata, ma la tua riga di codice sarà ancora visualizzare il valore 'BAZ!' .

Dettagli:

Come sottolineato da newacct , il codice NSLog funziona perché si utilizza l'operatore di assegnazione (=), che ha un comportamento molto specifico nel linguaggio C (che Objective-C si basa su)

In C, è possibile effettuare le seguenti operazioni:

x = y = z = 42;

e tutte le variabili, x, y e z conterrà il valore 42.

Il compilatore gestisce questo comportamento utilizzando una variabile temporanea (*). In sostanza, ciò che accade dietro le quinte simile a questa:

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

Sulla stessa linea, è possibile effettuare le seguenti operazioni:

SomeFunction(x = 42);

questa riga di codice copierà il valore di 42 in x, e quindi chiamare SomeFunction con un argomento di 42. Dietro le quinte, sembra che questo:

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

Ora, in Objective-C, la vostra linea di registrazione è gestita come segue:

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

(*) Si noti che l'utilizzo di una "variabile temporaray" descrivo intende illustrare il concetto, e non può effettivamente riflettere quello qualsiasi compilatore realmente fa sotto il cofano. Questo genere di dettaglio di implementazione spetta ai programmatori che scrivono il compilatore, e ognuno può fare qualcosa di diverso. Il risultato finale, tuttavia, è lo stesso.

Altri suggerimenti

Non c'è bisogno di chiamare un getter - ha il valore viene assegnato proprio lì sulla stessa linea. Si può pensare ad esso come espansione per [mcInst setFoobar:@"BAZ!"], @"BAZ!".

in C, assegnazione è un'espressione che restituisce il valore assegnato

Questo è a causa del modo in cui l'operatore di assegnamento C funziona. Come descritto nello standard ANSI C:

"L'operatore di assegnazione memorizza un valore nell'oggetto designato dal l'operando a sinistra. Un'espressione di assegnazione ha il valore di sinistra operando dopo l'assegnazione ... "

La vostra espressione assegnazione è mcInst.foobar = @"BAZ!". Sembra avere un senso per me che, anche se l'assegnazione funziona chiamando un metodo su mcInst comportamento lo stesso con C. Il valore dell'espressione assegnazione è l'operando a sinistra dopo l'assegnazione (@"BAZ!") quindi questo valore viene passato al funzione di NSLog.

Questo è lo stesso comportamento che consente di scrivere un initialiser nello stile di if (self = [super init]).

P.S. E 'una domanda giusta di chiedere perché sarebbe il compilatore chiamare il setter sulla proprietà quando si assegna il valore ad essa e non chiamare il getter quando si utilizza il valore di mcInst.foobar dopo. Direi che è semplicemente assunto il getter restituirà lo stesso valore che è stato appena assegnato alla proprietà e quindi il getter non viene chiamato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top