Подтвердить что ты не робот

MyView.frame.origin.x = значение; не работает. Но почему?

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

myView.frame.origin.x = 25.0;

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

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

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

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

4b9b3361

Ответ 1

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

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

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

  • a.b действительно является a.b;
  • a.b действительно является a.b = 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 источника, и теперь вы хотите что-то присвоить ему, и вот проблема...

Вы пытаетесь установить переменную struct struct, которая в порядке, но нет указателя из UIView на структуру, поэтому она копируется вместо этого. Таким образом, вы копируете, а затем устанавливаете, а затем ожидаете, что установленное действие каким-то образом перенаправлено через первоначальный доступ к 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

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

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

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

Ответ 3

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

Изменить: как было указано, назначение будет копией структуры.

Ответ 4

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

Изменить: Как указано в 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