@interface some_class : some_parent {
}
@property (nonatomic, assign) CGRect the_rect;
@end
...
@implementation some_class
@synthesize the_rect;
@end
创建some_class的实例后:
instance_of_some_class.the_rect.origin.x = 0.0;
生成“表达式无法分配”错误。
当然这很好用:
instance_of_some_class.the_rect = CGRectMake(0,0,0,0);
我想问题是自动神奇创建的setter只知道将CGRect分配给“the_rect”。好的,我明白了。我可以告诉它不要创建一个setter,这样我就可以直接访问成员变量并对struct成员进行赋值而不必分配整个CGRect吗?
我想我可以将它分解为四个单独的CGFloats for origin.x,origin.y,size.width和size.height ...但你认为有一种方法可以用CGRects代替它
令人困惑的是,这当然可行:
CGRect test = instance_of_some_class.the_rect.origin.x;
换句话说,getter知道如何导航struct并提取其中一个元素的值,以便我可以使用它。相反的情况似乎并非如此,因为你无法进入一个恰好是结构的ivar,并且无需分配整个结构就可以对其中一个元素进行赋值。
我也试过这个:
@interface some_class : some_parent {
@public
CGRect the_rect;
}
@property (nonatomic, assign) CGRect the_rect;
@end
在另一个模块中实例化后:
instance.the_rect->origin.x = some_value;
...并且错误地说被引用的成员不是指针。我尝试使用instance.the_rect的地址......但这也不起作用。
EDIT TO CLARIFY:这是关于创建一个具有一些碰巧结构的ivars的类。然后,在将该类实例化到其他地方后,您希望能够直接对struct ivar元素进行赋值:
class_instance.struct_ivar.element = something;
我正在使用CGRect作为一个众所周知的结构的一个方便示例,人们可能希望将其用作ivar。
答案 0 :(得分:12)
所以你知道如何解决你的问题,但是这里为什么你必须这样做,这就是为什么Objective-C中的点语法是一个邪恶的原因之一变态:
anInstance.property = blah
编译为完全相同的代码,如果您输入的话代码将生成:[anInstance setProperty:blah]
如果您的属性只是对象属性,则此方法可以正常工作。对我们来说不幸的是,点语法在C中已经具有不相关的含义,而这是为了访问结构的成员。即,你可以这样做:
NSRect foo;
foo.origin.x = 42;
如果foo
是对象,那么foo.origin.x = 42
将与[[foo origin] setX:42]
相同(假设origin
也是对象)。但是,由于它们只是结构,它只是进行偏移计算并直接在内存中设置值。没有方法调用。
在Objective-C中输入点语法。现在我们有点运算符的两个不同含义(甚至连C ++都不允许这样做,具有讽刺意味的是,它的所有运算符都被重载)。有时您使用它来访问结构成员。有时您正在使用它来调用对象访问器。有时您可以混合使用这些用途。有时你不能。
如果表达式用作右值,则可以混合使用成员与访问者访问。换句话说,你可以这样做:
foo = anObject.frame.origin.x;
但是,如果您尝试将此作为左值,则会失败:
anObject.frame.origin.x = foo;
解决这个问题的方法是:
NSRect frame = anObject.frame;
frame.origin.x = 42;
anObject.frame = frame;
当然,如果你只是忘记了点语法完全存在,那么你就永远不会遇到这个问题,因为尝试使用括号语法提出一种方法是不合情理的。
这是我认为点语法是一个可怕错误的众多原因之一。 永远如果从未添加过,就会对此感到困惑。
答案 1 :(得分:6)
您通常不直接从类外部访问成员变量。如果确实想要,您可以将其声明为@public
。我想你可能需要为每个rect的成员创建访问器:
- (void)setTheRectX:(CGFloat)newX {
the_rect.origin.x = newX;
}
- (void)setTheRectY:(CGFloat)newY {
the_rect.origin.y = newY;
}
- (void)setTheRectOrigin:(CGPoint)newOrigin {
the_rect.origin = newOrigin;
}
等等。
问题在于,当你要求实例的the_rect
时,你没有获得指向实例所具有的同一个矩形的指针,就像你将ivar作为一个对象指针一样 - 你会得到一个结构的新副本。
Public ivar:
@interface RectHolder : NSObject {
@public
CGRect the_rect;
}
访问:
RectHolder * myRH = [[RectHolder alloc] init];
myRH->the_rect = CGRectMake(0.0, 0.0, 100, 100);
myRH->the_rect.origin.x = 10;
NSLog(@"%@", NSStringFromRect(myRH->the_rect));
答案 2 :(得分:1)
您无法指定struct
的元素。这是你必须做的事情:
CGRect rect = object.rect;
rect.origin.x = 3.0f;
rect.size.height = 53.3f;
object.rect = rect;
通过执行此操作,您不会分配到rect的元素,而是更改整个rect值。
答案 3 :(得分:0)
这是你想要一个静态类变量,我现在知道它不是OP想要的。
如果你想要一个类变量,我不认为你是这样做的。我刚测试过,元素之间的价值不存在。不知道为什么它会让你在没有警告的情况下合成空的setter / getters。
对于创建类变量的方法,我认为最好的选择是使用static
关键字,就像在C.中一样。
static CGRect the_rect; // in .h file outside the @implementation
然后在+ (void)initalize
初始化它。你可能不得不亲自写下设置者和吸气剂。