myView.frame.origin.x = value; не работает - но почему?
Я знаю, что я не могу использовать это:
myView.frame.origin.x = 25.0;
и что я должен использовать это вместо:
CGRect myFrame = myView.frame;
myFrame.origin.x = 25.0;
myView.frame = myFrame;
И я делаю это все время, но я не знаю, почему я должен делать это таким образом. Я хотел бы восполнить этот пробел в моем понимании. Может кто-нибудь объяснить?
В настоящее время XCode дает вам "Выражение не присваивается". Некоторое время назад вы получили ошибку компиляции "Lvalue требуется как левый операнд присваивания".
4 ответа
Причина, по которой это не работает, заключается в смешении двух синтаксисов.
Сначала у вас есть "." в качестве ярлыка для вызова функций доступа (функция Objective-C). Так
- ab становится [a getB];
- ab = 5 становится [набор B:5];
А потом "." как прямой доступ к элементу структуры (чистый C). Так
- аб действительно есть аб;
- 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 может сам выполнить всю необходимую перенастройку.
Здесь используются два разных синтаксиса точек. Они выглядят одинаково, но делают разные вещи в зависимости от того, над чем они работают и что с этим делается:
- Первый
myView.frame
это сокращение для[myView frame]
вызов метода, который возвращаетCGRect
структурировать по значению. myFrame.origin.x
получает доступ к обычным членам структуры в традиционном C-стиле.- Второй
myView.frame
опять-таки сокращение, но поскольку оператор является присваиванием, он переводится в вызов другого метода,[myView setFrame:myFrame]
,
В вашем верхнем однострочном примере вы получаете копию прямоугольника и устанавливаете его x
, но никогда не копируйте его обратно в представление. Вы должны четко различать вызовы методов, так как синтаксис точки не может объединить их в один вызов.
CGRect
это структура, которая является чем-то из стандартного C. A CGRect
не является объектом Objective C, поэтому при назначении одному из его членов не вызывается метод установки. Без вызова метода установки UIKit не сможет узнать, что что-то изменилось, и, следовательно, не сможет обновить отображение на экране.
Редактировать: как уже было указано, назначение будет копии структуры.
Когда вы манипулируете данными напрямую, средство доступа не вызывается, поэтому пользовательский интерфейс не может обновлять себя или информировать любой другой компонент, который хочет знать об изменениях.
Редактировать: как указала 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