C99 designated initializers or CGMake Macros? - objective-c

Is C99 designated initializers or the various CGSizeMake, CZRectMake, etc macros more preferable as convention in modern Objective-C?
It almost seems like a personal style preference but the one advantage I see with the C99 style is that the intent of values is clear and explicit.
CGRect rect = CGRectMake(x, y, width, height)
would give you heartache if you mixed up the order of the values where as with:
CGRect rect = (CGRect){.origin.x = x, .origin.y = y, .size.width = width, .size.height = height};
there's no doubt that .height is getting the value you're giving it. What's the reason people would continue using the existing macros?
There's nothing in the Cocoa Coding Convention docs about this and one of the style guide I've come across that notes it is the GitHub style guide: https://github.com/github/objective-c-conventions

From Apple's CGGeometry reference:
All functions described in this reference that take CGRect data structures as inputs implicitly standardize those rectangles before calculating their results. For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics.
So, these CGRect functions (CGRectGetWidth, for example) will ensure height and width are always non-negative values. (CGRect functions that do not "take CGRect data structures as inputs", like CGRectMake, don't standardize the rect's dimensions.)
Additionally, the existing functions could be transitioned in the (admittedly extremely unlikely) event that the data structure ever changed.
Finally, despite the Github style guide you mentioned, the New York Times Objective-C Style Guide suggests using the CGRect functions (for the same reason I mentioned above).
Although it would be possible to use the inline functions when getting values from CGRects, and direct struct member access when creating them, this inconsistency could hurt code readability. Obviously, as you mentioned, it's a style question.
Basically, it doesn't matter, but use the functions.

Is C99 designated initializers or the various CGSizeMake, CZRectMake, etc macros more preferable as convention in modern Objective-C?
Neither style is objectively preferable in general. The formats of the CGRect, CGPoint, and CGSize structures are part of the public documentation, and thus effectively as unchangeable as the order of arguments to CGRectMake, so using a literal is fine. Whether to use literals or the Make functions is a matter of personal taste.
I tend to use CGRectMake instead of a literal when I have all the coordinates easily accessible. I prefer a literal when I'd otherwise have to either use an extra statement or send a message twice. For example, suppose I want to make a rectangle whose origin is (0,0) and whose size is the size of view. I could do that with CGRectMake like this:
CGRect rect = CGRectMake(0, 0, view.bounds.size.width, view.bounds.size.height);
But then I'm sending the bounds message twice. I could send it just once like this:
CGRect rect = view.bounds;
rect.origin = CGPointZero;
Or like this:
CGRect size = view.bounds.size;
CGRect rect = CGRectMake(0, 0, size.width, size.height);
But I prefer to use a literal like this:
CGRect rect = (CGRect){ .origin = CGPointZero, .size = view.bounds.size };
What's the reason people would continue using the existing macros?
Familiarity. Many people aren't familiar with the literal syntax, and they won't learn it by reading Apple's documentation.
A form of safety. If you use the macro, you're forced to provide all of the structure elements. You can't accidentally omit one.
On the other hand, you must put the elements in the correct order. So it's not strictly safer than a literal.

Related

Manipulating origin of a CGRect property through self. notation does not work but manipulating through ivar works [duplicate]

I know that I can't use this:
myView.frame.origin.x = 25.0;
and that I have to use this instead:
CGRect myFrame = myView.frame;
myFrame.origin.x = 25.0;
myView.frame = myFrame;
And I'm doing it all the time, but I don't know why I must do it that way. I would like to fill that gap in my understanding. Can someone explain ?
Nowadays Xcode gives you "Expression not assignable". Some time ago you got a compile error "Lvalue required as left operand of assignment".
There are two distinct dot syntaxes being used here. They look the same, but they do different things depending on what they are operating on and what is being done with it:
The first myView.frame is a shorthand for [myView frame], a method call that returns a CGRect struct by value.
myFrame.origin.x is accessing ordinary struct members in the traditional C fashion.
The second myView.frame is again a shorthand, but because the statement is an assignment it translates to calling a different method, [myView setFrame:myFrame].
In your single-line top example, you get a copy of the rect and set its x, but never copy it back to the view. You have to explicitly differentiate between the method calls, the dot syntax sugar can't magic them into a single call.
The reason this does not work is due to the mixing of two syntaxes.
First you have "." as a shortcut for calling the accessor functions (an Objective-C feature).
So
a.b becomes [a getB];
a.b = 5 becomes [a setB:5];
And then theres "." as direct struct member access (pure C). So
a.b really is a.b;
a.b really is a.b = 5;
Combining this in a set-value-case like this, doesn't work.
Because ...
If you could call
myView.frame.origin.x = 25.0;
The "myView.frame" part equals [myView getFrame] and you get a copied CGRect frame (a C struct)
The "myView.frame.origin" gives you a CGPoint origin (also a struct) of the copied CGRect
The "myView.frame.origin.x = 25.0" gives you a CGFloat x of the origin and now you want to assign something to it and here comes the problem...
You try to set a variable of a struct of a struct, which is ok, but there is no pointer from the UIView to the struct, so it is copied instead. So you copy and then you set and then you expect that the set action is somehow forwarded through the initial get to the UIView, well and this just doesn't work.
Of course you could wonder why Apple hasn't just created a shortcut, so that in the end your copied frame is automatically reinjected into a auto appended setFrame call, I guess you just have to live with how it is.
So remember, it would work if you'd get a pointer to the frame, but you don't, you get a copied struct instead.
So if you expect myView.frame.origin.x = 25.0 to work you indirectly expect your call to be automagically translated into some sort of
[myView setFrame:[myView getFrame:frame].origin.x = 25.0].
Well I guess you can admit that this looks wrong.
Also imagine if you'd get a direct pointer to the CGRect frame and you'd change something through that pointer, how would the UIView know that it's size has changed and that it has to update itself ? If on the other hand a [myView setFrame:newFrame] call is made, then UIView can do all the necessary readjusting itself.
A CGRect is a struct, which is something from standard C. A CGRect is not an Objective C object, so when you assign to one of its members, no setter method is called. Without a setter method being called, UIKit will not be able to know that anything has changed, and so will not be able to update the screen display.
Edit: as has been pointed out, the assignment will be to a copy of the struct.
When you manipulate the data directly, no accessor is called, so the UI cannot update itself - or inform any other component that wants to know about changes.
Edit: As pointed out by walkytalky, you will get a copy of the data, so changing it doesn't have any effect on the original anyway. The following example will show this:
UIView *aView = [[UIView alloc] initWithFrame:CGRectMake(50,50,100,100)];
NSLog(#"%f", aView.frame.origin.x); // will give 50
aView.frame.origin.x = 17; // operates on a copy of the rect only
NSLog(#"%f", aView.frame.origin.x); // will still give 50

Objective C syntax differences

I came across this kind of syntax a while ago :
[myView setFrame:({
CGRect frame = myView.frame;
frame.size.height = heightValue;
frame;
})];
I can't remember where I saw this, but I was wondering if there are any advantages in using it instead of the classic :
CGRect frame = myView.frame;
frame.size.height = heightValue;
[myView setFrame:frame];
The former syntax simply constrains the scope of frame such that the temporary storage that was used to create it can be reclaimed after the setFrame message send.
In my opinion however, this is one of those things that adds mental effort in reading code for an optimization that a compiler will almost certainly take anyway.
It prevents frame from being scoped outside of the call to setFrame:, but at the expense of readability.
The first syntax is a GNU extension to C language, called Statement Expression. It is incompatible with any of C standards, so you would be better off avoiding altogether in favor of the second syntax, which is a lot more readable.

A bracket + dot syntax issue

I have been working with Objective C for a couple of months now and this has been my first time seeing this type of syntax in objective c. I think I know the equivalent of it but I wanted to be sure.
Specifically, the code looks like this
float imageHeight = [player texture].contentSize.height;
What is the '[player texture].contentSize.height equivalent to?
I know that the dot and bracket syntax can be the same thing
something.backgroundColor = [UIColor redColor];
[something setBackgroundColor:[UIColor redColor]];
The above two are pretty much the same..
So is this what's happening in my first example? I just have never seen a mix of bracket and dot syntax into one.
Thank's.
float imageHeight = [player texture].contentSize.height;
This is probably the same thing as:
float imageHeight = [[player texture] contentSize].height;
Dot syntax translates to a call of the appropriate property accessor method when it's applied to object pointers. When applied to structures, it's a direct access of one of the fields of that structure.
So, assuming that [player texture] returns a pointer to an object (probably an image), the first use of dot syntax accesses that object's contentSize property. If -contentSize also returns an object pointer, then the next use would also translate to a call of an accessor. More likely, though, the contentSize property is a NSSize, and NSSize is a structure with width and height fields. So the second use of dot syntax most likely retrieves the height field from that structure.
Mixing the two different meanings of dot syntax works fine for getting a value, but you'll get an error if you try to use it to set values. If my assumptions in the previous paragraph are correct, you can't do this:
[player texture].contentSize.height = 50;

Objective C syntax query

Apologies or asking what is probably a very straightforward question, but I'm new to C-Syntax languages in general and have found something that confused me.
I've see a couple of example bits of code that create a CGFloat object and then seem to treat them as a implicit array of some kind, for example.
CGFloat newFloat[3] = {value1,value2,value};
Is this a generally valid concept in objective C to create arrays, or is it something built into CGFloat to hand 3D points in space?
Many thanks for any help.
This is called array initialisation and is a part of the language.
The {value1,value2,value} part is called an initialiser and can be used on the right side of the assignment whenever defining an array. When the number of elements in the initialiser corresponds to the specified size of the array, you don't actually need to explicitly specify the size:
CGFloat newFloat[] = {value1, value2, value};
This makes the maintenance easier since adding a new element at the end doesn't force you to update the size as well.
Such initialisers are supported for structs as well.
That's not an implicit array, the left hand side explicitly declares a variable that is a CGFloat array of length 3. The syntax is actually part of the C standard.

What's this {{0,0},{w,h}} doing?

I stumbled upon this piece of code today:
CGRect rect = {{0,0},{w,h}};
Here, I would have used a CGRectMake. But what does this thing in rambled brackets do? What kind of special-syntax is that? None of my objective-c books ever mentioned that.
It's a standard C structure initialization construct. Any structure can be initialized at declaration time by providing its contents in order within curly braces like this. Because a CGRect contains a CGPoint and a CGSize, you use one set of braces for the CGRect, then another set for each of CGPoint & CGSize.