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

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

myView.frame.origin.x = 25.0;

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

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

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

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

31
задан Josh Caswell 1 January 2013 в 22:07
поделиться

4 ответа

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

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

А затем есть "." как прямой доступ к членам структуры (чистый 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 origin (тоже структура) скопированного CGRect

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

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

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

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

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

18
ответ дан 27 November 2019 в 22:08
поделиться

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

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

2
ответ дан 27 November 2019 в 22:08
поделиться

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

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

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

40
ответ дан 27 November 2019 в 22:08
поделиться

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

Редактировать: Как указано в 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
1
ответ дан 27 November 2019 в 22:08
поделиться