I have class A with a header that looks something like this:
typedef struct {
int x;
int y;
} Position;
@interface ClassA : NSObject
@property Position currentPosition;
@end
And I try to assign individual values of the position struct from the property in another class like this:
ClassA * classA = [ClassA new];
classA.currentPosition.x = 10;
Which gives an error "expression is not assignable" and won't compile.
I can set it like this:
ClassA * classA = [ClassA new];
Position position = {
.x = 1,
.y = 2
};
classA.currentPosition = position;
And I can even alter individual "properties" of position
variable like this:
ClassA * classA = [ClassA new];
Position position = {
.x = 1,
.y = 2
};
// WORKS
position.x = 4;
// DOESN'T WORK
// classA.currentPosition.x = 4;
classA.currentPosition = position;
Why can't I set values individually when they are a property?
This expression:
classA.currentPosition
returns a temporary copy of your struct, not the struct itself. The compiler error is telling you that you can't assign a value to some member of that temporary copy (because it's an rvalue
, technically). But you don't want to assign a value to that member anyway, because it would just disappear along with the struct itself.
So why are you only getting a copy of the struct in the first place?
Because
@property Position currentPosition
is actually just shorthand for:
-(Position)currentPosition;
-(void)setCurrentPosition(Position value);
and in C-family languages, the first line (the getter) indicates that it's returning a Position struct by-value, or as a copy.
You could make your own accessor that returns a reference, but you probably shouldn't. This isn't a common idiom in Objective-C -- at least not in this context -- and you should generally try to stick with common idioms for a language.
Instead, you should use position like the following;
Position pos = classA.position;
pos.x = 4;
classA.position = pos;
Lastly, if you really want to be able to set currentPosition using the syntax you originally desired, while maintaing Objective-C idioms, you could just make Position a class rather than a struct. Then, the property can return a Position *
and the rest of the syntax would work. Make sure to initialize the pointer in your init
function (or when appropriate).
Properties don't work for C structs.
You can do it like:
@property Position *currentPosition;
Basically, using a pointer.
Now you actually need to initialize that pointer so:
- (id) init {
self = [super init];
if(self){
self.currentPosition = malloc(sizeof(Position));
}
return self;
}
Then, don't forget to use arrow notation, since you're dealing with a pointer:
classA.currentPosition->x = 5;
And don't forget to free the memory you requested!
-(void)dealloc{
free(self.currentPosition);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With