3

I have this:

typedef struct objTag{
    float x;
    float y;
    BOOL isUP;
} object;

how do I make object a property like this

@property (nonatomic, assign) object myObj;

and then...

@synthesize myObj = _myObj;

this compiles fine, but later in code when I try something like

self.myObj.isUP = YES;

I receive the message "expression is not assignable"

Stas
  • 9,925
  • 9
  • 42
  • 77
Duck
  • 34,902
  • 47
  • 248
  • 470
  • this was tagged with c++, why? – vikingosegundo Feb 14 '13 at 18:00
  • 3
    Protip: If you just copy and paste the error you're getting into Google, you can very often find the answer quickly. – Chuck Feb 14 '13 at 18:08
  • Another answer that pertains to your question (basically the same answer as you will find in the question @Chuck linked to, but a bit more to the point): http://stackoverflow.com/a/9412042/650350 – Mathew Feb 14 '13 at 18:10
  • @JoshCaswell It is not quite a duplicate, because it is talking about the possibility of modifying custom structs referred to by custom properties, rather than properties of Apple's closed-source classes. – Mathew Feb 14 '13 at 18:58
  • The class that the struct is a part of doesn't matter, @Mathew; the result of assigning to a member of the struct through the property is the same. – jscs Feb 14 '13 at 18:59
  • @JoshCaswell The OP is not asking "why it doesn't work" they are asking "how to make it work". My answer below addresses this, even though the practice of using struct pointers as properties is virtually unheard of. – Mathew Feb 14 '13 at 19:01

3 Answers3

6

This does not work because the compiler would compile this to:

[[self getMyOj] setIsUP: YES];

You'll note that 'isUP' is a property on a C struct not an Obj-C object ivar.

EDIT:

If you really wanted direct manipulation you would need to go about it like this.

typedef struct s {
    int i;
} s;

@interface Test : NSObject {
    s *myS;
}
@property (nonatomic, assign) s *myS;
@end

@implementation Test
@synthesize myS;
- (id) init {
    self = [super init];
    myS = malloc(sizeof(s));
    myS->i = 0;
    return self;
}
@end


// somewhere later.
Test *t = [[Test alloc] init];
t.myS->i = 10;

Note that you would want to clean up myS in your dealloc method.

Jared Kipe
  • 1,189
  • 6
  • 5
  • It does not, which is why it fails. The compiler will make assumptions, the dot syntax is ambiguous when you mix the two (Obj-C setters/getters and C-struct manipulation). – Jared Kipe Feb 14 '13 at 18:13
  • 2
    This is not actually what is going on. If it was just that the compiler could not tell whether isUp was a property or a struct element, then `((object)self.myObj).isUp = YES` would work. The compiler is throwing an error because the property accessor for `myObj` is returning a copy of the struct, rather than a reference to the struct the class holds. Editing it would not change the value of the struct the class holds, so the compiler throws an error to let the programmer know that there is no use case for that code. – Mathew Feb 14 '13 at 18:19
  • I have tested using ((object)self.myObj).isUp = YES and does not work either. Same message "expression is not assignable". Is there a way to build setters and getters that could return the correct object? – Duck Feb 14 '13 at 18:37
  • @RubberDuck see my answer to this question. It is possible to use properties to modify the struct referred to by a property, but it is not generally done because it is much messier than copying the struct. – Mathew Feb 14 '13 at 18:45
  • No, Mathew is correct. What is returned is a copy of the struct. This is how C-structs and functions/methods that return C-structs have to work. I will update my answer to show how you 'could' use c-structs with direct manipulation. – Jared Kipe Feb 14 '13 at 18:58
  • You need to add, free(t->myS); either there will be a memory link. – l0gg3r Feb 14 '14 at 12:10
3

This question gets back to the basics of C programming (i.e. non-object-oriented programming).

When you use a property that refers to a struct, you are grabbing a copy of that struct, not a reference to it.

If you write

CGRect rect = CGRectMake(...);
CGRect rect2 = rect;

You are not assigning rect2 a reference to rect, you are creating a copy of the struct. Changing rect2 does not change rect.

Similarly, if you change an element of a struct returned as a property, you are changing the element of a copy of the rect owned by your object. There is literally NO good that can come of this -- there is no use for this sort of code because you are changing the value of an element of a struct that there is no reference to anywhere.

If you wanted to edit the struct that was actually being used by the class, your property would need to return a pointer to it. This can be done, but the code becomes messier than it is worth:

typedef struct myObj{BOOL isUp;} TOBJECT;
...
@property (nonatomic, assign) TOBJECT* myObj; //in class interface

...

self.myObj = malloc(sizeof(TOBJECT)); //in init method.
...
self.myObj->isUp = YES; //elsewhere, even potentially outside the class.
...
free(self.myObj); //in class dealloc method.
Mathew
  • 1,788
  • 15
  • 27
0

This is just like dealing with frames on UIViews - you need to assign the entire struct in one shot, not its subvalues. So something like:

object obj = self.myObj;
obj.isUP = YES;
self.myObj = obj;

If you don't like that (it sucks!), don't use structs. Build a class with a couple properties on it instead. structs are really just there because obj-c is a superset of c, you should avoid them if you can. :)

escrafford
  • 2,373
  • 16
  • 19
  • 1
    I am tempted to vote down on this. structs have some benefits, as they are fast to create. and you should not avoid them where possible. – vikingosegundo Feb 14 '13 at 18:08
  • 1
    ditto. structs are not something to avoid. if you do not need methods, a struct is the efficient way of storing data. – Mathew Feb 14 '13 at 18:12
  • 2
    Really? Do you guys use structs in your code? I can't think of a single time in the last 9 years of objective-c programming that I needed a struct. Never have I needed that ever so tiny increase in performance that offset the headache of dealing with something that wasn't a real object. I hate not being able to extend CGRect/NSRect in cocoa code, and this silly three line idiom I have to type every time I modify a frame. You may as well argue that method calls in objective-c are too slow, and you should really just create c functions instead because they're faster. – escrafford Feb 14 '13 at 18:19
  • if creating a struct is too mich code for you, you can use some macro/C-function to cover that. and actually you deal with structs with every object you create as `typedef struct objc_class *Class; typedef struct objc_object { Class isa; } *id; ` – vikingosegundo Feb 14 '13 at 18:23
  • and yes: I am using structs. ie for high performance parsing of huge files. – vikingosegundo Feb 14 '13 at 18:25
  • 1
    We are arguing different points, I think. I am not saying that structs are really fun to work with as properties of objective-c classes. I am saying that structs are less work to define than a class AND ever-so-slightly less overhead as well. If I am writing an Objective-C class that only contains properties and no methods, I have to ask myself why I bothered with all the extra coding when I could have defined a struct so much more easily. – Mathew Feb 14 '13 at 18:25