我知道我不能使用这个:
myView.frame.origin.x = 25.0;
我必须改用这个:
CGRect myFrame = myView.frame;
myFrame.origin.x = 25.0;
myView.frame = myFrame;
而且我一直都在这样做,但我不知道为什么我必须那样做。我想填补我理解的空白。有人可以解释吗?
现在 Xcode 给你“表达不可分配”。前段时间你得到一个编译错误“需要左值作为赋值的左操作数”。
我知道我不能使用这个:
myView.frame.origin.x = 25.0;
我必须改用这个:
CGRect myFrame = myView.frame;
myFrame.origin.x = 25.0;
myView.frame = myFrame;
而且我一直都在这样做,但我不知道为什么我必须那样做。我想填补我理解的空白。有人可以解释吗?
现在 Xcode 给你“表达不可分配”。前段时间你得到一个编译错误“需要左值作为赋值的左操作数”。
这里使用了两种不同的点语法。它们看起来一样,但是根据它们的操作和正在执行的操作,它们会做不同的事情:
myView.frame
是 的简写,即按值返回结构[myView frame]
的方法调用。CGRect
myFrame.origin.x
以传统 C 方式访问普通结构成员。myView.frame
也是一个速记,但由于该语句是一个赋值,它转换为调用不同的方法,[myView setFrame:myFrame]
.在您的单行顶部示例中,您获得了 rect 的副本并设置了它x
,但从不将其复制回视图。您必须明确区分方法调用,点语法糖不能将它们魔术到单个调用中。
这不起作用的原因是由于混合了两种语法。
首先你有“。” 作为调用访问器函数的快捷方式(Objective-C 特性)。所以
然后是“。” 作为直接结构成员访问(纯 C)。所以
在这样的设置值情况下结合它是行不通的。
因为......如果你能打电话
myView.frame.origin.x = 25.0;
“myView.frame”部分等于 [myView getFrame] 并且你得到一个复制的 CGRect 框架(一个 C 结构)
“myView.frame.origin”为您提供复制的 CGRect 的 CGPoint 原点(也是一个结构)
“myView.frame.origin.x = 25.0”给你一个原点的CGFloat x,现在你想给它分配一些东西,问题就来了……
您尝试设置一个结构的结构的变量,这可以,但是没有从 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 可以自行进行所有必要的重新调整。
ACGRect
是一个结构,它来自标准 C。ACGRect
不是Objective C 对象,因此当您分配给它的一个成员时,不会调用任何 setter 方法。如果没有调用 setter 方法,UIKit 将无法知道发生了什么变化,因此无法更新屏幕显示。
编辑:正如已经指出的那样,分配将是结构的副本。
当您直接操作数据时,不会调用访问器,因此 UI 无法自行更新 - 或通知任何其他想要了解更改的组件。
编辑:正如 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