31 votes

myView.frame.origin.x = value ; ne fonctionne pas - Mais pourquoi ?

Je sais que je ne peux pas utiliser ça :

myView.frame.origin.x = 25.0;

et que je dois utiliser ceci à la place :

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

Et je le fais tout le temps, mais je ne sais pas pourquoi je dois le faire de cette façon. J'aimerais combler cette lacune dans ma compréhension. Quelqu'un peut-il m'expliquer ?

Aujourd'hui Xcode vous donne "Expression not assignable". Il y a quelques temps, vous obteniez une erreur de compilation "Lvalue required as left operand of assignment".

39voto

walkytalky Points 7065

Il y a deux syntaxes de points distinctes utilisées ici. Elles se ressemblent, mais elles agissent différemment en fonction de l'objet sur lequel elles opèrent et de ce qui est fait avec :

  • Le premier myView.frame est un raccourci pour [myView frame] un appel de méthode qui renvoie un CGRect struct par valeur .
  • myFrame.origin.x accède aux membres ordinaires de struct de la manière traditionnelle du C.
  • Le deuxième myView.frame est encore une fois un raccourci, mais parce que la déclaration est une affectation cela se traduit par l'appel d'une méthode différente, [myView setFrame:myFrame] .

Dans votre exemple de haut de page à une seule ligne, vous obtenez une copie du rect et définissez son x mais ne le recopie jamais dans la vue. Vous devez différencier explicitement les appels de méthode, le sucre syntaxique point ne peut pas les combiner en un seul appel.

17voto

Allisone Points 1142

La raison pour laquelle cela ne fonctionne pas est due au mélange de deux syntaxes.
Tout d'abord, vous avez "." comme raccourci pour appeler les fonctions d'accès (une caractéristique de l'Objective-C). Ainsi,

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

Et puis il y a "." comme accès direct aux membres de la structure (pur C). Donc

  • A.B. est vraiment A.B ;
  • a.b est réellement a.b = 5 ;

La combinaison de ces éléments dans un cas d'ensemble de valeurs comme celui-ci ne fonctionne pas.
Parce que... Si vous pouviez appeler

myView.frame.origin.x = 25.0;
  • La partie "myView.frame" est égale à [myView getFrame] et vous obtenez un cadre CGRect copié (une structure C).

  • Le "myView.frame.origin" vous donne un CGPoint d'origine (également un struct) du CGRect copié.

  • Le "myView.frame.origin.x = 25.0" vous donne un CGFloat x de l'origine et maintenant vous voulez lui attribuer quelque chose et voilà le problème...

Vous essayez de définir une variable d'un struct d'un struct, ce qui est correct, mais il n'y a pas de pointeur de l'UIView vers le struct, il est donc copié à la place. Donc vous copiez et ensuite vous définissez et ensuite vous vous attendez à ce que l'action de définition soit en quelque sorte transmise par le get initial à la UIView, et bien cela ne fonctionne pas.

Bien sûr, vous pouvez vous demander pourquoi Apple n'a pas simplement créé un raccourci, de sorte qu'à la fin, votre cadre copié est automatiquement réinjecté dans un appel setFrame ajouté automatiquement, je suppose que vous devez vivre avec la situation actuelle.

Rappelez-vous, cela fonctionnerait si vous obteniez un pointeur vers le cadre, mais ce n'est pas le cas, vous obtenez une structure copiée à la place.
Donc si vous attendez myView.frame.origin.x = 25.0 pour fonctionner, vous vous attendez indirectement à ce que votre appel soit automatiquement traduit en une sorte d'outil d'aide à la décision.
[myView setFrame:[myView getFrame:frame].origin.x = 25.0] .
Eh bien, je suppose que tu peux admettre que ça a l'air mauvais.

Imaginez également que vous obteniez un pointeur direct sur le cadre CGRect et que vous changiez quelque chose à travers ce pointeur, comment l'UIView saurait-il que sa taille a changé et qu'il doit se mettre à jour ? Si, par contre, un appel à [myView setFrame:newFrame] est effectué, alors l'UIView peut effectuer lui-même tous les réajustements nécessaires.

2voto

Emil Points 490

A CGRect est un struct, qui est quelque chose de standard C. Un CGRect est pas un objet Objective C, donc lorsque vous assignez à l'un de ses membres, aucune méthode setter n'est appelée. Sans l'appel d'une méthode setter, UIKit ne pourra pas savoir que quelque chose a changé, et ne pourra donc pas mettre à jour l'affichage de l'écran.

Edit : comme cela a été souligné, l'affectation se fera sur une copie de la structure.

1voto

Eiko Points 19502

Lorsque vous manipulez les données directement, aucun accesseur n'est appelé, de sorte que l'interface utilisateur ne peut pas se mettre à jour - ou informer tout autre composant qui souhaite être informé des changements.

Edit : Comme l'a souligné walkytalky, vous obtiendrez une copie des données, donc les modifier n'aura de toute façon aucun effet sur l'original. L'exemple suivant vous le montrera :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X