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