myView.frame.origin.x = значение; не работает - но почему? - PullRequest
31 голосов
/ 06 июня 2010

Я знаю, что не могу использовать это:

myView.frame.origin.x = 25.0;

и что я должен использовать это вместо:

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

И я делаю это все время, но я не знаю, почему я должен делать это таким образом. Я хотел бы восполнить этот пробел в моем понимании. Может кто-нибудь объяснить?

В настоящее время XCode дает вам «Выражение не присваивается». Некоторое время назад вы получили ошибку компиляции «Lvalue требуется как левый операнд присваивания».

Ответы [ 4 ]

40 голосов
/ 06 июня 2010

Здесь используются два разных синтаксиса точек. Они выглядят одинаково, но делают разные вещи в зависимости от того, над чем они работают и что с этим делается:

  • Первый myView.frame является сокращением для [myView frame], вызова метода, который возвращает CGRect struct по значению .
  • myFrame.origin.x обращается к обычным элементам структуры традиционным способом C.
  • Второй myView.frame снова является сокращением, но поскольку оператор является присваиванием , он переводится как вызов другого метода, [myView setFrame:myFrame].

В верхнем однострочном примере вы получаете копию прямоугольника и устанавливаете его x, но никогда не копируете его обратно в представление. Вы должны четко различать вызовы методов, так как синтаксис точки не может объединить их в один вызов.

18 голосов
/ 06 июня 2010

Причина, по которой это не работает, заключается в смешении двух синтаксисов.
Сначала у вас есть "."в качестве ярлыка для вызова функций доступа (функция Objective-C).Таким образом,

  • ab становится [a getB];
  • ab = 5 становится [setB: 5];

И затем появляется "."как прямой доступ к элементу структуры (чистый C).Таким образом,

  • ab на самом деле является ab;
  • ab на самом деле является ab = 5;

Объединение этого в случае набора значений, как это, не делаетне работает.
Потому что ... Если бы вы могли вызвать

myView.frame.origin.x = 25.0;
  • Часть "myView.frame" равна [myView getFrame], и ​​вы получите скопированный кадр CGRect (структура C)

  • «myView.frame.origin» дает вам источник CGPoint (также структура) скопированного CGRect

  • «MyView.frame.origin.x = 25.0» дает вам CGFloat x источника, и теперь вы хотите присвоить ему что-то, и здесь возникает проблема ...

Выпопробуйте установить переменную структуры структуры, что нормально, но нет указателя от UIView на структуру, поэтому вместо этого она копируется.Таким образом, вы копируете, а затем устанавливаете, а затем ожидаете, что действие set каким-то образом перенаправляется через начальный переход к UIView, и это просто не работает.

Конечно, вы могли бы задаться вопросом, почему Apple не просто создала ярлык, так что в итоге ваш скопированный кадр автоматически повторно вводится в автоматически добавленный вызов setFrame, я думаю, вам просто нужно жить с тем, как оно есть.

Запомните, это сработало бы, если бы вы получили указатель на фрейм, но не получили, вместо этого вы получите скопированную структуру.
Так что, если вы ожидаете, что myView.frame.origin.x = 25.0 сработает, выкосвенно ожидать, что ваш вызов будет автоматически переведен в какой-то тип
[myView setFrame:[myView getFrame:frame].origin.x = 25.0].
Ну, я думаю, вы можете допустить, что это выглядит неправильно.

Также представьте, если вы получите прямой указатель накадр CGRect, и вы бы что-то изменили с помощью этого указателя, как бы UIView узнал, что его размер изменился и что он должен сам обновиться?Если, с другой стороны, выполняется вызов [myView setFrame: newFrame], тогда UIView может сам выполнить всю необходимую перенастройку.

2 голосов
/ 06 июня 2010

A CGRect - это структура, которая является чем-то стандартным C. A CGRect - это , а не объект Objective C, поэтому, когда вы присваиваете одному из его членов, метод set не вызывается , Без вызова метода установки UIKit не сможет узнать, что что-то изменилось, и, следовательно, не сможет обновить экран.

Редактировать: как было указано, присваивание будет копии структуры.

1 голос
/ 06 июня 2010

Когда вы манипулируете данными напрямую, средство доступа не вызывается, поэтому пользовательский интерфейс не может обновлять себя или информировать любой другой компонент, который хочет знать об изменениях.

Редактировать: Как указала walkytalky, вы получите копию данных, поэтому ее изменение никак не повлияет на оригинал. Следующий пример покажет это:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...