Objective-C
NSArray
CGPoint
iOS Development
Programming Tips

How can I add CGPoint objects to an NSArray the easy way?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

CGPoint is a C struct, while NSArray stores Objective-C objects. Because of that mismatch, points must be boxed before insertion into Objective-C collections. The standard approach is using NSValue, which safely wraps and unwraps Core Graphics structs. This pattern is stable, readable, and compatible with both legacy Objective-C APIs and mixed Swift projects.

Store CGPoint Values with NSValue

Use valueWithCGPoint: when adding points to mutable arrays.

objective-c
1#import <Foundation/Foundation.h>
2#import <CoreGraphics/CoreGraphics.h>
3
4NSMutableArray<NSValue *> *points = [NSMutableArray array];
5
6CGPoint p1 = CGPointMake(10.0, 20.0);
7CGPoint p2 = CGPointMake(30.5, 40.25);
8
9[points addObject:[NSValue valueWithCGPoint:p1]];
10[points addObject:[NSValue valueWithCGPoint:p2]];
11
12NSLog(@"count: %lu", (unsigned long)points.count);

This is the cleanest method for Objective-C APIs that need array storage.

Read Points Back Correctly

Unbox with CGPointValue before geometry operations.

objective-c
1for (NSValue *boxed in points) {
2    CGPoint p = [boxed CGPointValue];
3    NSLog(@"x=%.2f y=%.2f", p.x, p.y);
4}

Avoid pointer casts or manual memory tricks. NSValue handles layout correctly.

Use Typed Collections for Clarity

Modern Objective-C supports lightweight generics for readability:

objective-c
1NSArray<NSValue *> *pathPoints = @[
2    [NSValue valueWithCGPoint:CGPointMake(0, 0)],
3    [NSValue valueWithCGPoint:CGPointMake(50, 75)]
4];

This helps static analysis and makes intent clear during reviews.

Bridge with Swift Cleanly

Swift arrays can store CGPoint directly. When crossing Objective-C boundaries, convert explicitly.

swift
1let objcPoints: [NSValue] = [
2    NSValue(cgPoint: CGPoint(x: 1, y: 2)),
3    NSValue(cgPoint: CGPoint(x: 3, y: 4))
4]
5
6let swiftPoints: [CGPoint] = objcPoints.map { $0.cgPointValue }
7print(swiftPoints)

Keep boxing at boundaries so internal Swift logic can use value types directly.

Reusable Helper Functions

If your code frequently boxes points, helper functions reduce noise.

objective-c
1NSArray<NSValue *> *BoxCGPoints(const CGPoint *points, NSUInteger count) {
2    NSMutableArray<NSValue *> *result = [NSMutableArray arrayWithCapacity:count];
3    for (NSUInteger i = 0; i < count; i++) {
4        [result addObject:[NSValue valueWithCGPoint:points[i]]];
5    }
6    return result;
7}

Central helpers also reduce copy-paste bugs across rendering modules.

Performance Considerations

Boxing and unboxing has overhead. For performance-sensitive loops such as hit testing thousands of points per frame, prefer native buffers or Swift [CGPoint] internally, then box only when required by Objective-C APIs.

Good pattern:

  • compute with native point arrays,
  • convert to an NSValue array only at API boundary.

This balances speed and interoperability.

Validate Round-Trip Accuracy

Add quick tests for precision and order preservation.

objective-c
1CGPoint source = CGPointMake(12.5, -3.75);
2NSValue *boxed = [NSValue valueWithCGPoint:source];
3CGPoint restored = [boxed CGPointValue];
4
5BOOL same = CGPointEqualToPoint(source, restored);
6NSLog(@"round trip ok: %@", same ? @"YES" : @"NO");

Include negative and fractional coordinates in tests, especially for drawing and layout code.

Convenience Category for Cleaner Call Sites

If your project stores many geometric structs, a small category around NSValue improves readability and avoids accessor mistakes.

objective-c
1@interface NSValue (CGPointBoxing)
2+ (instancetype)mq_valueWithPoint:(CGPoint)p;
3- (CGPoint)mq_pointValue;
4@end

Using project-specific names can make code search easier and enforce consistent boxing conventions across modules.

Common Pitfalls

  • Trying to insert raw CGPoint structs directly into NSArray.
  • Using the wrong unboxing accessor for stored struct types.
  • Performing geometry math on boxed values without unboxing first.
  • Overusing boxed point arrays in tight rendering loops.
  • Mixing coordinate spaces without documenting expected input and output.

Summary

  • 'CGPoint must be boxed as NSValue for Objective-C array storage.'
  • Use valueWithCGPoint: and CGPointValue for safe conversion.
  • Keep boxing at API boundaries when working with Swift value arrays.
  • Add helpers and tests for clarity and reliability.
  • Prefer native point containers in performance-critical paths.

Course illustration
Course illustration

All Rights Reserved.