Question

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

Was it helpful?

Solution 2

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?

  1. Familiarity. Many people aren't familiar with the literal syntax, and they won't learn it by reading Apple's documentation.

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

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top