MyView.marco.origen.x = valor; no funciona-Pero ¿por qué?


Sé que no puedo usar esto:

myView.frame.origin.x = 25.0;

Y que tengo que usar esto en su lugar:

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

Y lo estoy haciendo todo el tiempo, pero no se por qué debo hacerlo de esa manera. Quisiera llenar ese vacío en mi comprensión. ¿Alguien puede explicarlo ?

Hoy en día Xcode le da "Expresión no asignable". Hace algún tiempo tienes un error de compilación "Lvalue required as left operand of assignment".

Author: Josh Caswell, 2010-06-06

4 answers

Aquí se utilizan dos sintaxis de puntos distintas. Se ven iguales, pero hacen cosas diferentes dependiendo de lo que están operando y lo que se está haciendo con él:

  • La primera myView.frame es una abreviatura de [myView frame], una llamada a un método que devuelve una estructura CGRect por valor.
  • myFrame.origin.x está accediendo a los miembros de la estructura ordinaria en la forma tradicional de C.
  • El segundo myView.frame es de nuevo una abreviatura, pero porque la declaración es una asignación se traduce en llamar a un método diferente, [myView setFrame:myFrame].

En su ejemplo superior de una sola línea, obtiene una copia del rect y establece su x, pero nunca lo copia de nuevo a la vista. Tienes que diferenciar explícitamente entre las llamadas al método, la sintaxis punto sugar no puede mágicamente en una sola llamada.

 40
Author: walkytalky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-06 11:04:08

La razón por la que esto no funciona se debe a la mezcla de dos sintaxis.
Primero tienes "."como atajo para llamar a las funciones del accessor (una característica de Objective-C). So

  • a. b se convierte en [un getB];
  • a. b = 5 se convierte en [un setB:5];

Y luego hay"."as direct struct member access (pure C). So

  • a. b es realmente a. b;
  • a. b es realmente a. b = 5;

Combinar esto en un set-value-case como este, no funciona.
Porque ... Si pudiera llamar

myView.frame.origin.x = 25.0;
  • El " MyView.frame " parte es igual a [MyView getFrame] y se obtiene un marco CGRect copiado (una estructura C)

  • El " MyView.marco.origin " le da un origen CGPoint (también una estructura) del CGRect copiado

  • El " MyView.marco.origen.x = 25.0 " te da un CGFloat x del origen y ahora quieres asignarle algo y aquí viene el problema...

Intenta establecer una variable de una estructura de una estructura, lo cual está bien, pero no hay ningún puntero de la UIView a la estructura, por lo que se copia en su lugar. Por lo que copiar y, a continuación, establecer y, a continuación, se espera que la acción de conjunto es de alguna manera reenviado a través de la inicial llegar a la UIView, bien y esto simplemente no funciona.

Por supuesto, podría preguntarse por qué Apple no solo ha creado un acceso directo, de modo que al final su marco copiado se reinyecta automáticamente en una llamada setFrame auto anexada, supongo que solo tiene que vivir con cómo es.

So recuerde, funcionaría si usted conseguiría un indicador al marco, pero usted no, usted consigue una estructura copiada en su lugar.
Así que si esperas que myView.frame.origin.x = 25.0 funcione, indirectamente esperas que tu llamada se traduzca automáticamente en algún tipo de
[myView setFrame:[myView getFrame:frame].origin.x = 25.0].
Bueno, supongo que puedes admitir que esto se ve mal.

También imagine que si obtiene un puntero directo al marco CGRect y cambia algo a través de ese puntero, ¿cómo sabría el UIView que su tamaño ha cambiado y que tiene que actualizarse ¿en sí mismo ? Si por otro lado se hace una llamada a [MyView setFrame:newFrame], entonces UIView puede hacer todo el reajuste necesario por sí mismo.

 17
Author: Allisone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-14 13:00:04

A CGRect es una estructura, que es algo del estándar C. A CGRect es no un objeto Objective C, por lo que cuando se asigna a uno de sus miembros, no se llama a ningún método setter. Sin un método setter que se llama, UIKit no será capaz de saber que algo ha cambiado, y por lo tanto no será capaz de actualizar la pantalla de visualización.

Editar: como se ha señalado, la asignación será a una copia de la estructura.

 2
Author: Emil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-06 12:45:19

Cuando manipula los datos directamente, no se llama a ningún accessor, por lo que la interfaz de usuario no puede actualizarse a sí misma, ni informar a ningún otro componente que quiera conocer los cambios.

Editar: Como señala walkytalky, obtendrá una copia de los datos, por lo que cambiarlos no tiene ningún efecto en el original de todos modos. El siguiente ejemplo mostrará esto:

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
 1
Author: Eiko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-01 22:02:51