2010-06-06 14 views
31

So che non posso usare questo:myView.frame.origin.x = valore; non funziona - Ma perché?

myView.frame.origin.x = 25.0; 

e che devo usare questo, invece:

CGRect myFrame = myView.frame; 
myFrame.origin.x = 25.0; 
myView.frame = myFrame; 

e sto facendo tutto il tempo, ma non lo faccio sai perché devo farlo in quel modo. Vorrei colmare questa lacuna nella mia comprensione. Qualcuno può spiegare?

Al giorno d'oggi Xcode offre "Espressione non assegnabile". Qualche tempo fa hai ricevuto un errore di compilazione "Lvalue richiesto come operando sinistro dell'assegnazione".

+1

+1 - Mi stavo chiedendo per un po 'di tempo ora .. – Emil

risposta

17

Il motivo per cui questo non funziona è dovuto al mixaggio di due sintassi.
Prima di tutto "." come scorciatoia per chiamare le funzioni accessorie (una funzione Objective-C). Quindi

  • a.b diventa [a getB];
  • a.b = 5 diventa [a setB: 5];

E poi c'è "."Come l'accesso diretto struct membro (puro C) Così

  • ab è davvero ab;.
  • ab è davvero ab = 5;

Combinando questo in un set-value-caso come questo , non funziona.
Perché ... Se si potrebbe chiamare

myView.frame.origin.x = 25.0; 
  • La parte "myView.frame" è uguale a [myView GetFrame] e si ottiene un telaio CGRect copiato (un C struct)

  • Il "myView.frame.origin" ti dà origine CGPoint (anche una struct) del copiato CGRect

  • il "myView.frame.origin.x = 25,0" ti dà una CGFloat x dell'origine e ora si desidera assegnare qualcosa ad esso e qui viene il problema ...

Si tenta di impostare una variabile di una struttura di una struct, che è ok, ma non vi è alcun puntatore da UIView alla struct, quindi viene invece copiato. Quindi copi e poi imposti e poi ti aspetti che l'azione del set venga in qualche modo inoltrata attraverso l'iniziale di arrivare a UIView, beh, e questo semplicemente non funziona.

Ovviamente ci si potrebbe chiedere perché Apple non abbia appena creato una scorciatoia, in modo che alla fine il fotogramma copiato venga automaticamente reinserito in una chiamata setFrame con l'aggiunta automatica, immagino che devi solo vivere con quello che è.

Quindi ricorda che funzionerebbe se avessi un puntatore al frame, ma non lo fai, ottieni invece una struct copiata.
Quindi, se si prevede che myView.frame.origin.x = 25.0 funzioni, la tua chiamata verrà automaticamente tradotta in una sorta di
[myView setFrame:[myView getFrame:frame].origin.x = 25.0].
Beh, immagino che si possa ammettere che questo sembra sbagliato.

Immaginate anche se otterreste un puntatore diretto al frame CGRect e cambiereste qualcosa attraverso quel puntatore, in che modo l'UIView saprebbe che le sue dimensioni sono cambiate e che deve aggiornarsi? Se invece viene effettuata una chiamata [myView setFrame: newFrame], quindi UIView può eseguire tutto il necessario riaggiustamento.

1

Quando si manipolano i dati direttamente, non viene richiamato alcun utente, quindi l'interfaccia utente non può aggiornarsi autonomamente o informare qualsiasi altro componente che desidera conoscere le modifiche.

Modifica: come indicato da walkytalky, si otterrà una copia dei dati, quindi la modifica non ha alcun effetto sull'originale. L'esempio seguente mostra questo:

UIView *aView = [[UIView alloc] initWithFrame:CGRectMake(50,50,100,100)]; 
NSLog(@"%f", aView.frame.origin.x); // will give 50 
aView.frame.origin.x = 17; // operates on a copy of the rect only 
NSLog(@"%f", aView.frame.origin.x); // will still give 50 
+0

Penso che dovresti ottenere un "Lvalue richiesto come operando a sinistra del compito" dal compilatore prima. – Allisone

+0

ancora mi ha capito. grazie – Allisone

+0

Nessun avvertimento del compilatore qui ... – Eiko

2

Un CGRect è una struttura, che è qualcosa da serie C. A CGRect è non un oggetto Objective C, in modo che quando si assegna a uno dei suoi membri, senza setter il metodo è chiamato. Senza chiamare un metodo setter, UIKit non sarà in grado di sapere che qualcosa è cambiato e quindi non sarà in grado di aggiornare la visualizzazione dello schermo.

Modifica: come è stato sottolineato, l'incarico riguarderà una copia della struttura.

39

Qui ci sono due distinte sintassi dei punti. Hanno lo stesso aspetto, ma lo fanno cose diverse a seconda di ciò che stanno funzionando e che cosa si sta facendo con esso:

  • Il primo myView.frame è una scorciatoia per [myView frame], una chiamata di metodo che restituisce un CGRect struct da valore.
  • myFrame.origin.x accede ai membri della struct ordinaria nel modo tradizionale C.
  • Il secondo myView.frame è di nuovo una stenografia, ma poiché l'istruzione è un assegnazione si traduce in chiamata a un metodo diverso, [myView setFrame:myFrame].

Nell'esempio in alto a linea singola, si ottiene una copia del rect e si imposta x, ma non si copiano mai nuovamente la vista. Devi distinguere esplicitamente tra le chiamate al metodo, lo zucchero della sintassi del punto non può magiarle in una singola chiamata.

+2

ottima spiegazione! – reflog

Problemi correlati