Question

Log CGPoint and CGRect in Objective-C with NSLog

cobjective-ccocoacocoa-touch

Question

How can I debug and log C structures such as CGPoint or CGRect in Objective-C without manually writing every property each time?

For example, I would like to write something similar to:

CGPoint cgPoint = CGPointMake(0, 0);
NSLog(@"%@", cgPoint);

I understand that %@ does not work here because CGPoint is not an Objective-C object. What is the correct approach?

Short Answer

You will learn why Objective-C's %@ format specifier cannot print C structs, how Apple-provided conversion functions make Core Graphics types readable, and how to log your own structs safely.

Concept

CGPoint, CGSize, and CGRect are C structures. A structure groups several values into one value, but it is not an Objective-C object.

NSLog uses format specifiers:

  • %@ expects an Objective-C object, such as an NSString, NSArray, or NSNumber.
  • %d, %f, and similar specifiers expect scalar C values.
  • A C struct has its own memory layout, so it cannot be passed where %@ expects an object pointer.

For common Core Graphics structures, the framework provides functions that convert the struct into an NSString:

  • NSStringFromCGPoint
  • NSStringFromCGSize
  • NSStringFromCGRect

This is useful because a readable log can quickly show incorrect coordinates, sizes, or layout frames while debugging an app.

For a custom C struct, there is no automatic, universal %@ formatter. Usually, you write a small helper function that creates a descriptive string from its fields.

Mental Model

Think of %@ as a label printer designed for objects. An Objective-C object carries information about how it can describe itself.

A CGPoint is more like a sealed package containing two numbers, x and y. The label printer cannot open and interpret that package automatically.

NSStringFromCGPoint is a translator: it opens the package and produces a text label such as {0, 0} that NSLog can print with %@.

Take Quiz

Syntax and Examples

Use the conversion function that matches the Core Graphics type.

CGPoint point = CGPointMake(12.5, 40.0);
CGSize size = CGSizeMake(320.0, 44.0);
CGRect frame = CGRectMake(10.0, 20.0, 320.0, 44.0);

NSLog(@"point: %@", NSStringFromCGPoint(point));
NSLog(@"size: %@", NSStringFromCGSize(size));
NSLog(@"frame: %@", NSStringFromCGRect(frame));

Each NSStringFrom... function returns an NSString. Because the returned value is an object, %@ is now the correct format specifier.

A possible log output is:

point: {12.5, 40}
size: {320, 44}
frame: {{10, 20}, {320, 44}}

For a custom struct, format its individual members in a helper:

typedef struct {
    NSInteger identifier;
    CGFloat opacity;
} LayerInfo;

static NSString *NSStringFromLayerInfo(LayerInfo info) {
    return [NSString stringWithFormat:@"{ identifier: %ld, opacity: %.2f }",
            (long)info.identifier,
            info.opacity];
}

LayerInfo info = { .identifier = 42, .opacity = 0.75 };
NSLog(@"layer: %@", NSStringFromLayerInfo(info));

The cast to (long) matches %ld, which is a common safe choice for logging NSInteger.

Step by Step Execution

Consider this code:

CGPoint point = CGPointMake(8.0, 16.0);
NSString *pointDescription = NSStringFromCGPoint(point);
NSLog(@"Selected position: %@", pointDescription);
  1. CGPointMake(8.0, 16.0) creates a CGPoint struct whose x is 8.0 and whose y is 16.0.
  2. NSStringFromCGPoint(point) reads the struct and creates an Objective-C NSString representation, similar to @"{8, 16}".
  3. pointDescription stores a pointer to that NSString object.
  4. %@ tells NSLog to print the object description.
  5. The console receives a readable message similar to:
Selected position: {8, 16}

By contrast, this is invalid:

NSLog(@"%@", point);

point is a struct value, not an object pointer that %@ can use.

Real World Use Cases

Core Graphics structs occur frequently in Apple-platform applications:

  • Touch handling: log a tap location with NSStringFromCGPoint(location).
  • Auto Layout and view debugging: log view.frame, view.bounds, or view.center with NSStringFromCGRect and NSStringFromCGPoint.
  • Image and drawing code: inspect crop rectangles, drawing bounds, and canvas sizes.
  • Animation debugging: verify a view's starting and ending frames.
  • Geometry calculations: compare expected and actual positions after applying offsets, scaling, or coordinate conversion.

Example when investigating a layout issue:

NSLog(@"card frame: %@, container bounds: %@",
      NSStringFromCGRect(cardView.frame),
      NSStringFromCGRect(containerView.bounds));
Take Quiz

Real Codebase Usage

In production code, logging is usually made consistent and easy to remove or filter.

Log meaningful context

Avoid logging an isolated rectangle when the surrounding state matters:

NSLog(@"[ProfileHeader] avatar frame=%@ hidden=%@",
      NSStringFromCGRect(self.avatarView.frame),
      self.avatarView.hidden ? @"YES" : @"NO");

Put custom formatting in one helper

If a custom struct appears in several places, create one formatter rather than repeating format strings:

typedef struct {
    CGFloat red;
    CGFloat green;
    CGFloat blue;
} RGBColor;

static NSString *NSStringFromRGBColor(RGBColor color) {
    return [NSString stringWithFormat:@"RGB(%.2f, %.2f, %.2f)",
            color.red, color.green, color.blue];
}

This keeps logs uniform and ensures that a future struct change is updated in one location.

Use the debugger for one-off inspection

For a variable you only need to inspect once, LLDB can often print it directly:

(lldb) p point

Use source-level logging when the value must be observed during an asynchronous flow, reproduced in a test run, or recorded alongside other application events.

Common Mistakes

Passing a struct to %@

Broken code:

CGPoint point = CGPointMake(1, 2);
NSLog(@"%@", point);

Why it fails: %@ expects an Objective-C object pointer, while point is a struct.

Fix:

NSLog(@"%@", NSStringFromCGPoint(point));

Treating a struct as a pointer

Broken code:

NSLog(@"%@", &point);

&point is a pointer to struct memory, not an Objective-C object. %@ still does not apply.

Using the wrong numeric format specifier in a custom formatter

Broken code:

NSInteger count = 10;
NSLog(@"count: %d", count);

NSInteger can have a different size from int. Prefer %ld with a cast:

NSLog(@"count: %ld", (long)count);

Logging only part of a rectangle

NSLog(@"width: %f", frame.size.width);

This is valid, but it can hide a wrong origin or height. During geometry debugging, logging the entire CGRect is often more useful:

NSLog(@"frame: %@", NSStringFromCGRect(frame));

Assuming every struct has a built-in conversion function

The NSStringFrom... helpers are supplied for common framework types. Your own struct needs its own formatting helper unless its framework documents one.

Comparisons

Value being loggedWhat it isRecommended approach
NSString *nameObjective-C objectNSLog(@"%@", name)
NSInteger countInteger scalarNSLog(@"%ld", (long)count)
CGFloat amountFloating-point scalarNSLog(@"%g", (double)amount)
CGPoint pointC structNSLog(@"%@", NSStringFromCGPoint(point))
CGSize sizeC structNSLog(@"%@", NSStringFromCGSize(size))
CGRect rectC structNSLog(@"%@", NSStringFromCGRect(rect))
Custom structC structWrite a helper that returns NSString *

NSValue can also box some structs into an Objective-C object:

NSValue *boxedPoint = [NSValue valueWithCGPoint:point];
NSLog(@"%@", boxedPoint);

This can be convenient when an API requires an object, such as storing a point in an array. For clear logging, NSStringFromCGPoint(point) directly communicates your intention.

Take Quiz

Cheat Sheet

// Core Graphics structs
NSLog(@"%@", NSStringFromCGPoint(point));
NSLog(@"%@", NSStringFromCGSize(size));
NSLog(@"%@", NSStringFromCGRect(rect));

// Scalars
NSLog(@"integer: %ld", (long)integerValue);
NSLog(@"decimal: %g", (double)decimalValue);

// Custom struct: create a formatter that returns NSString *
static NSString *NSStringFromMyStruct(MyStruct value) {
    return [NSString stringWithFormat:@"{ a: %d, b: %.2f }", value.a, value.b];
}

NSLog(@"%@", NSStringFromMyStruct(value));

Rules:

  • %@ is for Objective-C objects.
  • A C struct is not an Objective-C object.
  • Convert framework structs to strings before using %@.
  • Do not pass a struct or a pointer-to-struct to %@.
  • Use a named helper for custom struct descriptions reused across a project.

FAQ

Can I use %@ directly with a CGPoint?

No. CGPoint is a C struct, while %@ expects an Objective-C object.

How do I print a CGRect with NSLog?

Use NSStringFromCGRect:

NSLog(@"%@", NSStringFromCGRect(rect));

How do I log a CGSize?

Use NSStringFromCGSize(size) and print the resulting string with %@.

Can I use NSValue to log a CGPoint?

Yes. NSValue can box supported structs into an object. It is especially useful when an API needs an object, but NSStringFromCGPoint is more explicit for logging.

Is there a generic format specifier for every C struct?

No. Format strings must know the type and layout of their arguments. Use a framework conversion function when available, or write a formatter for your own struct.

Why cast NSInteger to long when logging?

NSInteger changes size between architectures. (long) together with %ld avoids a format mismatch.

What should I use to inspect a struct just once during debugging?

Use LLDB's p command, such as p point, when you do not need the value recorded by application logging.

Take Quiz

Mini Project

Description

Build a small geometry-debugging utility for a view layout. The utility logs a panel's frame, its center point, and whether the frame fits inside a container rectangle. It demonstrates converting Core Graphics structs to readable strings before logging them.

Goal

Log readable geometry information and identify whether a panel frame is contained within its container.

Requirements

Create a CGRect for a container and a CGRect for a panel. Log both rectangles using the appropriate NSStringFrom... conversion function. Log the panel's center as a CGPoint. Use CGRectContainsRect to determine whether the panel fits inside the container. Log a clear success or warning message based on the result.

Take Quiz

Keep learning

Related questions

View more