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

7
  • 1
    Care to show us the declaration of Point? Commented Nov 6, 2015 at 7: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!) Commented Nov 6, 2015 at 7:22
  • 1
    You're thinking of NSPoint and CGPoint; those are standard structs for holding x/y co-ords. Commented Nov 6, 2015 at 7:23
  • @dumbledad And there's your problem: You can't put any type into a Cocoa array. Just Objective-C objects. Commented Nov 6, 2015 at 7: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? Commented Nov 6, 2015 at 7:41

4 Answers 4

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.

Sign up to request clarification or add additional context in comments.

Comments

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

1 Comment

There is a good chance that Point is a C++ class; until we see the declaration we are in the dark.
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

6 Comments

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.
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...) stackoverflow.com/questions/5091163/how-to-use-nspointarray
It's a poor solution. Why not vector<Point>?
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 !! ;)
I am a dinosaur from assembly and C times :D Anyway, the point is to use pointer to the structure, via *, [ ], or <vector>. They all work. dumbledad will choose according to what he manipulates the best in C. Cheers @trojanfoe, you're a nice guy :)
|
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.

2 Comments

That's an unrelated problem in the original code. I removed this from the question because it distracted from the actual question.
Hmm - good call. I rolled back your edit thinking it was misguided; but it wasn't! Sorry Nikolai.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.