6

Dire che ho il seguente:L'assegnazione di proprietà Objective-C restituisce il valore assegnato?

@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 

Poi:

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 qui che questa linea sarebbe stampare I set 'foobar' to '', perché l'assegnazione sembra di tornare nulla .

Tuttavia - per fortuna - questa assegnazione agisce come previsto, e le stampe di codice I set 'foobar' to 'BAZ!'. Sfortunatamente, questo sembra una contraddizione, perché il valore di ritorno del setter invocato smentisce il fatto che l'assegnazione restituisce il valore assegnato ad esso. Inizialmente ho pensato che lo mcInst.foobar = @"BAZ!"; stia effettuando due chiamate anziché un blocco: prima il setter e poi il getter per raccogliere il valore di ritorno. Tuttavia, strumentare i metodi setter e getter con le chiamate NSLog dimostra che questo non è il caso.

+1

Penso piuttosto che "Perché funziona NSLog?", Una domanda migliore (e penso che la domanda che stai ponendo) sia "perché il setter restituisce nulla, e non (in questo caso) NSString *? avevo supposto che mcInst.foobar = fosse solo zucchero sintattico per [mcInst setFoobar: ...] Suppongo di no ... –

+1

Sì, la domanda è: perché il compilatore genera un errore quando si usa 'NSLog (@" I set ' foobar 'a'% @ '", [mcInst setFoobar: @" BAZ! "]);' riconoscendo che il metodo non restituisce nulla, ma ti permette di farlo nell'altro modo. – Dimitris

+0

Brian: sì, quello era in effetti la domanda che stavo cercando di porre, anche se la mia formulazione potrebbe aver nascosto che =) – rpj

risposta

9

Sommario 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 vostro setFoobar metodo:

- (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 mostrerà ancora 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); 

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

+0

Capisco il comportamento C e come viene realizzato dal compilatore. Suppongo che il tuo punto di vista del compilatore che usa una variabile temporanea abbia senso, quindi grazie. Tuttavia, il punto centrale della mia domanda era l'apparente contraddizione tra un metodo che restituisce il vuoto (che è ciò che la sintassi della proprietà in Objective-C si riduce a) e l'assegnazione che restituisce il valore assegnato. – rpj

+1

Hmm. Penso che avrei potuto seppellire il concetto chiave sotto troppi dettagli. Se date un'occhiata all'ultimo blocco di codice nella mia risposta, potete vedere perché l'uso di una variabile temporanea rende irrilevante il valore di ritorno dell'accessorio della proprietà. La proprietà accessor viene semplicemente chiamata come una delle fasi nell'esecuzione della riga 'NSLog (...)', ed è la variabile temporanea che viene passata a 'NSLog'. –

+0

Ho messo il punto critico in cima alla mia risposta e ho aggiunto un altro esempio che potrebbe aiutare a illustrare. Spero possa essere d'aiuto! –

0

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

+0

Capisco, e persino l'ho fatto notare. Sto cercando i dettagli dell'applicazione di Objective-C. – rpj

0

Ciò è dovuto al modo in cui l'operatore di assegnazione C funziona. Come descritto nello standard ANSI C:

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

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

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

P.S. È una domanda giusta chiedere perché il compilatore dovrebbe chiamare il setter sulla proprietà quando assegna il valore ad esso e non chiamare il getter quando si utilizza il valore di mcInst.foobar in seguito. Direi che è semplicemente scontato che il getter restituisca lo stesso valore che è stato appena assegnato alla proprietà e quindi il getter non viene chiamato.

1

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