3

I'm reading a book about iOS (it calls Programming iOS 4, by Matt Neuburg) and in the paragraph where he explains properties he said these words:

Objective-C uses dot-notation for properties, and C uses dot-notation for structs; these can be chained. So, for example, UIView’s frame is a property whose value is a struct (a CGRect); thus, you can say myView.frame.size.height, where frame is a property that returns a struct, size is a component of that struct, and height is a component of that struct. But a struct is not a pointer, so you cannot (for example) set a frame’s height directly through a chain starting with the UIView, like this:

myView.frame.size.height = 36.0; // compile error

Instead, if you want to change a component of a struct property, you must fetch the property value into a struct variable, change the struct variable’s value, and set the entire property value from the struct variable:

CGRect f = myView.frame;
f.size.height = 0;
myView.frame = f;

I don't understand well, why I can't use the line below?

myView.frame.size.height = 36.0;
jv42
  • 8,521
  • 5
  • 40
  • 64
Fred Collins
  • 5,004
  • 14
  • 62
  • 111
  • 1
    See this [answer](http://stackoverflow.com/a/5861985/165737). – Anurag Feb 21 '12 at 05:11
  • 2
    possible duplicate of [How to gain assignment access to CGRect elements when the CGRect is an instance variable](http://stackoverflow.com/questions/5860755/how-to-gain-assignment-access-to-cgrect-elements-when-the-cgrect-is-an-instance) – Costique Feb 21 '12 at 05:20

3 Answers3

3

Background

A variable in a programming language is a box which has a name (sometimes termed a "reference" or a "pointer' depending on the language). This box contains a value of some type. Values don't change, the contents of boxes do. E.g in the following code:

int a = 4;
a = 5;

The second line doesn't change 4, it changes what is in box a.

Types in programming languages fall into two categories: value types and reference types.

For value types what gets passed around and stored in boxes is a representation of the actual value, e.g. in the code:

double a = 9.0;
double b = sqrt(a);

The function sqrt is not passed a but the value that is stored in a - which is some sequence of bits which represent the number 9.0; what is returned by sqrt is some sequence of bits which represent 3.0, and these are stored into b. The bits that are passed around, you use your words in one of your comments, are the "real value".

For reference types what gets passed around and stored in boxes is some representation of the name of the box (chunk of memory) which contains the actual value. In Objective-C reference types are distinguished by using * in their declaration (other languages don't require a *, e.g. Java & C# - they know which types are reference types based on their kind). E.g in the code:

NSWindow *main = [NSApp mainWindow];

the method call doesn't return a window value itself but the name of a box containing the window value. Again to use your words, the "real value" is never passed around rather the name of a box containing that value is passed around.

Traditionally "small" types were represented by value types - integers, floating point numbers, characters, etc.; while "large" values by reference types. However each programming languages makes its own choices - some are even defined to only operate with reference types.

Answer

In your example myView.frame is a property, and a property is implemented using a method. In Objective-C (and C, C++) a struct type is a value type - it is treated just like integers and floating point numbers, it's value is passed around and stored in boxes. So what is returned by the property is, using your words, the "real struct" - it's as "real" as the bits representing 3.0 in the above example.

What isn't being returned is the name of the box containing a struct value, and without access to a box you can't change its contents. Which is why myView.frame.size.height = 36.0; is incorrect - you're trying to change part of a value, and values don't change.

However given an NSRect box you can change part of its contents. E.g. in the code:

NSRect aRect;
aRect.size.height = 36.0;

The .size.height is identifying which part of the box aRect to change, and the representation of 36.0 is stored into that part of the box.

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86
2

Because if you broke it all out, myView.frame is the same as saying

CGRect aFrame = [myView frame]

which gives you back a copy of the struct, not a pointer back to the "real" struct. Thus the compiler is helping you by not letting you set a value in a temporary struct that will not reflect in the "real" struct.

Kendall Helmstetter Gelner
  • 74,769
  • 26
  • 128
  • 150
  • Thanks man. So even when I use `float height = myView.frame.size.height` it returns a copy of the frame struct and not the real one? (that in this case it's okay because the values are the same) – Fred Collins Feb 21 '12 at 05:43
  • And can you tell me why `[myView frame]` or `[self myStruct]` give me a copy of the struct and not the real struct? – Fred Collins Feb 21 '12 at 06:05
  • That's just how properties work for data values, they make copies. Otherwise when you got a value back you'd have to undo the pointer reference to get to something like an int or a struct, and lots of things could be modified with unexpected side-effects. – Kendall Helmstetter Gelner Feb 21 '12 at 06:50
1
myView.frame

will return you a struct which is a Rvalue not Lvalue. For rvalue and lvalue read this
Now myView.frame will return rvalue which is a data not a pointer.

Inder Kumar Rathore
  • 39,458
  • 17
  • 135
  • 184