Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting values in a custom struct as property in Objective-C [duplicate]

Tags:

objective-c

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?

like image 567
Logan Avatar asked Apr 24 '14 23:04

Logan


2 Answers

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).

like image 198
adpalumbo Avatar answered Oct 17 '22 15:10

adpalumbo


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);
}
like image 31
manecosta Avatar answered Oct 17 '22 14:10

manecosta