1

I'm having trouble with what must be a fairly simple task: adding objects to an NSMutableArray in Objective-C. Here are the million ways I have tried already:

NSMutableArray* foregroundPoints;

Point point;

// Fails with "No viable conversion from 'Point' to 'id _Nonnull'"
[foregroundPoints addObject: point];

// Fails with "Cannot initialise a parameter of type 'id _Nonull' with an rvalue of type 'Point *'"
[foregroundPoints addObject: &point];

// Fails with: "Illegal type 'Point' used in boxed expression"
[foregroundPoints addObject: @(point)];

Point *pointPtr;

// Fails with "Cannot initialise a parameter of type 'id _Nonull' with an lvalue of type 'Point *'"
[foregroundPoints addObject: pointPtr];

// Fails with "Cannot initialise a parameter of type 'id _Nonull' with an rvalue of type 'Point **'"
[foregroundPoints addObject: &pointPtr];

//Fails with: "Illegal type 'Point *' used in boxed expression"
[foregroundPoints addObject: @(pointPtr)];

What should I be doing to add the Point to my NSMutableArray?

(N.B. From the comments and some of the answers I see that I was confused about Point. I'd assumed it was an Objective-C library class but in fact it was a C++ struct picked up from elsewhere in my project. So my question really boils down to this: how do I add a CGPoint to an NSMutableArray? I'll leave the main question unedited as the discussion in the comments and the answers that don't conflate Point and CGPoint are also interesting.)

dumbledad
  • 16,305
  • 23
  • 120
  • 273
  • 1
    Care to show us the declaration of `Point`? – trojanfoe Nov 06 '15 at 07:20
  • Oh, interesting - I'd assumed that was a basic Objective-C thing! I'll check where that's coming from (possibly deep within some C++ I'm trying to marshall!) – dumbledad Nov 06 '15 at 07:22
  • 1
    You're thinking of `NSPoint` and `CGPoint`; those are standard `struct`s for holding x/y co-ords. – trojanfoe Nov 06 '15 at 07:23
  • @dumbledad And there's your problem: You can't put any type into a Cocoa array. Just Objective-C objects. – Nikolai Ruhe Nov 06 '15 at 07:23
  • It is a C++ struct - doh! I'll pass in a CGPoint instead. I'm not sure whether to edit the question to change Point to CGPoint or leave it and ask again? – dumbledad Nov 06 '15 at 07:41
  • Boxing of C++ types is a bit more involved (due to C++ construction/destruction semantics). If you can move to CGPoint, that's best. I'd leave the question in place and just add a short edit with this note. – Nikolai Ruhe Nov 06 '15 at 07:44
  • The question is also misleading. It should be tagged as objective-c++ and have its title corrected. – trojanfoe Nov 06 '15 at 07:53

4 Answers4

3

As others noted NSArray only holds Objective-C objects. To hold C types you need to box them in objects.

You need to use NSValue or NSString here. NSValue has boxing methods for most common Foundation structs and primitives.

There are also functions that also convert to and from NSString for several of these. See the Foundation Functions Reference.

Scalar C types can be boxed and unboxed using the NSValue subclass NSNumber

nil has to be represented using NSNull

uchuugaka
  • 12,679
  • 6
  • 37
  • 55
3

The issue is that only objects can be added to collections such as NSArray or NSDictionary.

Convert your "point" (likely a CGPoint or NSPoint struct) into an NSValue object that can be added to the array.

Use this class to work with such data types in collections (such as NSArray and NSSet), key-value coding, and other APIs that require Objective-C objects.

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSValue_Class/

For example, use + valueWithCGPoint: to convert the point to an NSValue representation that can be added to the array.

CGPoint point;
NSValue *pointValue = [NSValue valueWithCGPoint:point];
[foregroundPoints addObject:pointValue];

Then, later, use - CGPointValue to convert the object back to the original type.

pkamb
  • 33,281
  • 23
  • 160
  • 191
1

@pkamb answer is the way.

However, if you need performance, use a standard C array to store your points rather than do multiple calls to valueWithCGPoint and CGPointValue.

Embed it in a NSObject ( named PointArray, for example ) to do the manipulation.

@interface PointArray : NSObject

-(Point)pointAtIndex:(NSUInteger)index;
-(void)addPoint:(Point)point;

…

@property(nonatomic,readonly) NSUInteger numberOfPoints;

@end

@implementation PointArray
{
    Point     *points;
    NSUInteger numberOfPoints;
}

// You'll have to work a bit there ..

@end
Moose
  • 2,607
  • 24
  • 23
  • I've marked @pkamb's as the answer, but I'll actually run with this one, since it may prove more useful for how I'm using the array later in the code. – dumbledad Nov 06 '15 at 08:52
  • 1
    That works great until you need a different sized array and it comes with the the dangers and pains of C arrays. If you REALLY need performance, you step into the dark world of Objective-C++ and use a Vector. Until then, have a look at NSPointArray ( a simple typedef, but it's there...) http://stackoverflow.com/questions/5091163/how-to-use-nspointarray – uchuugaka Nov 06 '15 at 08:56
  • 1
    It's a poor solution. Why not `vector`? – trojanfoe Nov 06 '15 at 09:00
  • Yes, you are right. Quickly wrote - to give the principle. However I would not say it is a "poor" solution- simply not the best - You are harsh @trojanfoe !! ;) – Moose Nov 06 '15 at 09:05
  • No, "poor" is a toned-down version of what I really think. Managing collections like this went out with the Dinosaurs. – trojanfoe Nov 06 '15 at 09:07
  • 1
    I am a dinosaur from assembly and C times :D Anyway, the point is to use pointer to the structure, via *, [ ], or . They all work. dumbledad will choose according to what he manipulates the best in C. Cheers @trojanfoe, you're a nice guy :) – Moose Nov 06 '15 at 09:24
0

You are trying to initialise NSMutableArray object with NSArray.

why don't you try this...

foregroundPoints = [NSMutableArray arrayWithObjects: @(startPoint), @(endPoint), nil];

Initialise NSMutableArray foregroundPoints to NSMutableArray not with NSArray.

Mahendra
  • 8,448
  • 3
  • 33
  • 56
  • That's an unrelated problem in the original code. I removed this from the question because it distracted from the actual question. – Nikolai Ruhe Nov 06 '15 at 07:31
  • Hmm - good call. I rolled back your edit thinking it was misguided; but it wasn't! Sorry Nikolai. – dumbledad Nov 06 '15 at 07:36