Beware of struct properties
Objective-C is an interesting programming language. Unlike C++, it’s a strict superset of C — every valid C program is a valid Objective-C program. While most C programs are valid C++ programs, there are certain incompatibilities such as the introduction of new keywords that make the relationship not strict.
One of the many features that Objective-C brings is properties. Properties essentially act like public member variables, but whenever you get or set them, those gets and sets get rerouted through a function call (more specifically, the passing of a message in Objective-C parlance). For example, if value
is a property of whatever class my_object
belongs to, then the code
int x = my_object.value;
gets converted into
int x = [my_object value]; // pass the 'value' message to my_object
And this code
my_object.value = 3;
gets converted into
// pass the 'setValue' message with parameter 3 to my_object [my_object setValue:3];
Getters and setters allow you to do things like parameter validation, logging, or anything else you want whenever a property is read from or written to. The dot notation is just syntactic sugar.
Now suppose that value
isn’t a simple integer, but rather a struct of some sort, such as a CGPoint
. A CGPoint
is a standard 2D point class, containing two float members named x
and y
. Consider the following innocent-looking code:
my_object.value.x = 3; // set x-coordinate to 3?
If value
were just a plain ordinary struct member, this would do exactly what you’d expect – set the x-coordinate to 3, and leave the y-coordinate untouched. But as you’ve probably surmised by now, that’s not what happens when value
is a property. Why not? Well, since we’re not assigning to it, it gets turned into this:
[my_object value].x = 3;
And [my_object value]
returns an object of type CGPoint
. And structs are returned…..by value. Thus, we’re assigning 3 to the x-coordinate of a temporary CGPoint
which is a copy of our object’s value
property. The only proper way to resolve this is to make value
a regular class member and not a property, reassign a completely new CGPoint
to value
, or add messages that allow you to independently set the x- and y-coordinates. Depending on whether or not you own the code for the class, this may or not be possible.
Fortunately, in the case of CGPoint
s, it’s relatively easy to assign a new value with CGPointMake():
my_object.value = CGPointMake(3, my_object.value.y);
But for more complicated structs, this solution could be less than ideal.