“Expression is not assignable” -- 在Xcode中将两个float相加后作为另一个float的值进行赋值时出现问题?

43
在一个钢琴应用中,我正在分配黑键的坐标。以下是导致错误的代码行。
'blackKey'和'whiteKey'都是自定义视图。
blackKey.center.x = (whiteKey.frame.origin.x + whiteKey.frame.size.width);

请注意,whiteKey.frame.origin.x + whiteKey.frame.size.widthCGRectGetMaxX(whiteKey.frame)是相同的。 - ThomasW
5个回答

83
其他答案并没有完全解释这里发生了什么,所以这是基本的问题:当您编写 blackKey.center.x 时,blackKey.centercenter.x 都看起来像结构成员访问,但它们实际上是完全不同的东西。 blackKey.center 是一个属性访问,它会被转换为类似 [blackKey center] 这样的东西,然后再转换为类似 objc_msgSend(blackKey, @selector(center)) 这样的东西。您无法修改函数的返回值,例如 objc_msgSend(blackKey, @selector(center)).x = 2 — 因为返回值未存储在任何有意义的位置,所以这只是没有意义的。因此,如果您想修改结构体,您需要将属性的返回值存储到变量中,修改变量,然后将属性设置为新值。

我们可以设置 anObject.anNonStructProperty.anProperty = someValue,对吧?那么如何表达我们不能修改函数的返回值呢?你能解释一下吗? - EmptyStack
4
当你写anObject.someProperty = something时,它不等同于[anObject someProperty] = something,而是等同于[anObject setSomeProperty:something]。你正在向对象发送一条消息,调用一个setter方法。你并没有给这个方法的返回值赋值。出现赋值的外观只是语法糖,就像成员访问的外观是一个getter方法的语法糖一样。 - Chuck
我还是不太清楚。即使在你的答案中,blackKey.center 内部调用的是 objc_msgSend(blackKey, @selector(setCenter:)) 而不是 objc_msgSend(blackKey, @selector(center)) 对吗? - Adithya
@Adithya:不是的。如果你认为blackKey.center调用了setCenter:,那么你认为参数是什么?[blackKey setCenter: ?????]。实际上只是[blackKey center] - Chuck

19

如果一个CGPoint是对象的属性,你不能直接更改它的x值(或者结构体的任何值),需要使用以下方法:

CGPoint _center = blackKey.center;
_center.x =  (whiteKey.frame.origin.x + whiteKey.frame.size.width);
blackKey.center = _center;

10
blackKey.center = CGPointMake ( whiteKey.frame.origin.x + whiteKey.frame.size.width, blackKey.center.y);

一种方法。


0

根据其含义,您不能为表达式赋值。例如,a + b = c是被禁止的。


0

使用宏的一种替代方案:

#define CGPOINT_SETX(point, x_value) { \
    CGPoint tempPoint = point;         \
    tempPoint.x = (x_value);           \
    point = tempPoint;                 \
}

#define CGPOINT_SETY(point, y_value) { \
    CGPoint tempPoint = point;         \
    tempPoint.y = (y_value);           \
    point = tempPoint;                 \
}

CGPOINT_SETX(blackKey.center, whiteKey.frame.origin.x + whiteKey.frame.size.width);

或稍微简单一些:

CGPOINT_SETX(blackKey.center, CGRectGetMaxX(whiteKey.frame));

1
你真的需要 do ... while(0) 吗?使用块作用域 { ... } 能否足以声明临时变量(避免与外部定义的变量重名),并确保内部语句只执行一次? - Nicolas Miari
@NicolasMiari 我一直使用 do ... while(0) 这种方式已经很长时间了,以至于我没意识到 {...} 块也能很好地工作。谢谢,让代码更简洁了。 - ThomasW
1
do ... while(0) 的原因在这里:https://dev59.com/qXVC5IYBdhLWcg3w4Vb6 对于我的情况来说并不是必要的,但有些情况下是必须的。 - ThomasW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接