我知道我不能用这个:
myView.frame.origin.x = 25.0;
我必须改用它:
CGRect myFrame = myView.frame;
myFrame.origin.x = 25.0;
myView.frame = myFrame;
而且我一直这样做,但我不知道为什么我必须这样做。我想在我的理解中填补这个空白。谁能解释一下?
现在Xcode为您提供“Expression not assignable”。前段时间你得到一个编译错误“Lvalue需要作为赋值的左操作数”。
答案 0 :(得分:40)
这里使用了两种不同的点语法。它们看起来是一样的,但它们根据它们的操作以及使用它做了什么来做不同的事情:
myView.frame
是[myView frame]
的简写,这是一个按值返回CGRect
struct 的方法调用。myFrame.origin.x
正在以传统的C方式访问普通的struct成员。myView.frame
也是一个简写,但由于该语句是赋值,它转换为调用其他方法[myView setFrame:myFrame]
。在单行顶部示例中,您将获得rect的副本并设置其x
,但不要将其复制回视图。你必须明确地区分方法调用,点语法糖不能将它们变成单个调用。
答案 1 :(得分:17)
这不起作用的原因是由于两种语法的混合 首先你有“。”作为调用访问器函数的快捷方式(Objective-C功能)。 所以
然后theres“。”作为直接结构成员访问(纯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到结构的指针,因此它被复制。所以你复制然后你设置然后你期望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可以自行完成所有必要的调整。
答案 2 :(得分:2)
CGRect
是一个结构,它来自标准C.A CGRect
不是一个Objective C对象,所以当你分配给它的一个成员时,没有调用setter方法。如果没有调用setter方法,UIKit将无法知道任何更改,因此无法更新屏幕显示。
编辑:正如已经指出的那样,赋值将是结构的副本。
答案 3 :(得分:1)
当您直接操作数据时,不会调用任何访问者,因此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