当CGRect是实例变量时,如何获得对CGRect元素的赋值访问

mar*_*n's 7 iphone objective-c

@interface some_class : some_parent {

 }
@property (nonatomic, assign) CGRect the_rect;

@end

...

@implementation some_class

@synthesize the_rect;

@end
Run Code Online (Sandbox Code Playgroud)

创建some_class的实例后:

instance_of_some_class.the_rect.origin.x = 0.0;
Run Code Online (Sandbox Code Playgroud)

这会生成"表达式无法分配"错误.

当然这很好用:

instance_of_some_class.the_rect = CGRectMake(0,0,0,0);
Run Code Online (Sandbox Code Playgroud)

我想问题是,自动神奇创建的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;
Run Code Online (Sandbox Code Playgroud)

换句话说,getter知道如何导航struct并提取其中一个元素的值,以便我可以使用它.相反的情况似乎并非如此,因为你无法进入一个恰好是结构的ivar,并且无需分配整个结构就可以对其中一个元素进行赋值.

我也试过这个:

@interface some_class : some_parent {

@public

    CGRect the_rect;

 }
@property (nonatomic, assign) CGRect the_rect;

@end
Run Code Online (Sandbox Code Playgroud)

在另一个模块中实例化之后:

instance.the_rect->origin.x = some_value;
Run Code Online (Sandbox Code Playgroud)

...并且得到一个错误,说被引用的成员不是指针.我尝试使用instance.the_rect的地址......但这也不起作用.

EDIT TO CLARIFY:这是关于创建一个类似于结构的ivars的类.然后,在将类实例化到其他地方后,您希望能够直接对struct ivar元素进行赋值:

class_instance.struct_ivar.element = something;
Run Code Online (Sandbox Code Playgroud)

我正在使用CGRect作为一个众所周知的结构的一个方便的例子,人们可能希望将其用作ivar.

Dav*_*ong 12

所以你知道如何解决你的问题,但是这就是你必须这样做的原因以及为什么Objective-C中的点语法是一种邪恶的变态的原因之一:

anInstance.property = blah 编译为完全相同的代码,如果你改为输入将生成: [anInstance setProperty:blah]

如果您的属性只是对象属性,则此方法正常.对我们来说不幸的是,点语法在C中已经具有不相关的含义,而这是为了访问结构的成员.即,你可以这样做:

NSRect foo;
foo.origin.x = 42;
Run Code Online (Sandbox Code Playgroud)

如果foo是一个对象,那么foo.origin.x = 42将是相同的[[foo origin] setX:42](假设origin也是一个对象).但是,由于它们只是结构,它只是进行偏移计算并直接在内存中设置值.没有方法调用.

在Objective-C中输入点语法.现在我们有点运算符的两个不同含义(甚至连C++都不允许这样做,具有讽刺意味的是,它的所有运算符都被重载).有时您使用它来访问结构成员.有时您正在使用它来调用对象访问器.有时您可以混合使用这些用途.有时你不能.

如果表达式用作右值,则可以混合使用成员与访问者访问.换句话说,你可以这样做:

foo = anObject.frame.origin.x;
Run Code Online (Sandbox Code Playgroud)

但是,如果您尝试将此作为左值,则会失败:

anObject.frame.origin.x = foo;
Run Code Online (Sandbox Code Playgroud)

解决这个问题的方法是:

NSRect frame = anObject.frame;
frame.origin.x = 42;
anObject.frame = frame;
Run Code Online (Sandbox Code Playgroud)

当然,如果你只是忘记了点语法完全存在,那么你就永远不会遇到这个问题,因为尝试使用括号语法提出一种方法是非常不合情理的.

这是我认为点语法是一个可怕的错误的众多原因之一.如果从未添加过,你永远不会对此感到困惑.


Jos*_*ell 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;
}
Run Code Online (Sandbox Code Playgroud)

等等.

问题在于,当你要求实例时the_rect,你没有获得指向实例所具有的同一个矩形的指针,就像你将ivar作为一个对象指针一样 - 你得到一个新的结构副本.

围绕着SO讨论这个问题有几个问题:1 2 3

公共伊娃:

@interface RectHolder : NSObject {

@public
    CGRect the_rect;


}
Run Code Online (Sandbox Code Playgroud)

访问:

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));
Run Code Online (Sandbox Code Playgroud)