How to use NSPointArray? - objective-c

So I want to use the method appendBezierPathWithPoints:count: in NSBezierPath. But the method requires me to use NSPointArray. The documentary doesn't really talk much about it and all I could get about it is that it's an array of NSPoints and I'm not sure how to do it. I think that it uses the c array mechanism, but I'm not sure.
Thanks.

Yes, you need a C-style array of points to pass to appendBezierPathWithPoints:count:. For example you might do something like this:
NSPoint pointArray[3];
pointArray[0] = NSMakePoint(0, 0);
pointArray[1] = NSMakePoint(0.5, 0.25);
pointArray[2] = NSMakePoint(1, 1);
[lines appendBezierPathWithPoints:pointArray count:3];
where lines is an instance of NSBezierPath.
In a more complicated case you'll use a variable number of points say.

If you want to use Objective-C style array, then you have to use NSValue class for this purpose.
NSMutableArray *array = [NSMutableArray array];
CGPoint myPoint;
myPoint.x = 100;
myPoint.y = 200;
[array addObject:[NSValue valueWithPoint:myPoint]];
To retrieve an NSPoint back from the array:
myPoint = [array[0] pointValue];
Hope it helps.

Related

How to use bridge for CLLocationCoordinate2D

AM trying to add CLLocationCoordinate2D[] to NSMutableArray and send it as parameter. But (__bridge id) is crashing the app. Struct to id conversion is the problem. Could anyone please let me know how to use this please.
CLLocationCoordinate2D coordinates[1000];
coordinates[index] --- all the coordinates added to it in loop.
NSMutableArray *coorArray = [NSMutableArray array];
[coorArray addObject:(__bridge id)(coordinates)]; crashes here
Use:
NSMutableArray *coorArray = [NSMutableArray array];
[coorArray addObject:[NSValue valueWithPointer:coordinates]];
Then when you want to retrieve the array of struct:
CLLocationCoordinate2D coordinates[] = [coorArray objectAtIndex:0].pointerValue;
A C array is not an object, so it can't be bridged.
You should look at +[NSValue valueWithBytes:objCType:] not a (__bridge) cast. Bridge is for other things.
e.g.:
[NSValue value:&coordinate withObjCType:#encode(CLLocationCoordinate2D)];
I guess it's possible to encode whole array too

"for x in" syntax with NSArray

I've this kind of instruction:
[self someMethod:CGPointMake(50, 50)];
[self someMethod:CGPointMake(270, 50)];
[self someMethod:CGPointMake(50, 360)];
[self someMethod:CGPointMake(270, 360)];
...
I want to refactor code using NSArray like this:
NSArray items = [NSArray initWithObjects:
CGPointMake(50, 50),
CGPointMake(270, 50),
CGPointMake(50, 360),
CGPointMake(270, 360),
...
nil];
I dont know right syntax, can someone help me? I'd tried with this, but XCode tells me "Selector element type CGPoint is not a valid object":
CGPoint point = [CGPoint alloc];
for (point in items) {
[self someMethod:point];
}
for-in loops are an Objective-C concept for iterating over collection classes (that conform to NSEnumeration). If you would like to iterate over C-structs (like CGPoints), use a standard for-loop with a C-array, or wrap the CGPoints in NSValues.
Here's what your refactoring would look like in modern Objective-C syntax:
NSArray *items = #[
[NSValue valueWithPoint:CGPointMake(50, 50)], //wrap the points in an
[NSValue valueWithPoint:CGPointMake(270, 50)], //NSValue so they become
[NSValue valueWithPoint:CGPointMake(50, 360)], //first class citizens
[NSValue valueWithPoint:CGPointMake(270, 360)],//(Y no boxing?*)
]; //End of collection literal
for (NSValue *value in items) { //iterate through the NSValues with our points
[self someMethod:[value pointValue]]; //'un-wrap' the points by calling -pointValue
}
*My personal struct boxing macro:
#define STRUCT_BOX(x) [NSValue valueWithBytes:&x objCType:#encode(typeof(x))];
There's no need to resort to NSArray. As CodaFi says, "If you would like to iterate over C-structs (like CGPoints), use a standard for-loop with a C-array." Well then, why not do so?
static CGPoint items[] = {
{50, 50},
{270, 50},
{50, 360},
{270, 360},
};
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
This creates the array at compile-time, not run-time! Then iterate the array:
for (NSUInteger i = 0; i < ARRAY_SIZE(items); ++i)
[self someMethod:items[i]];
For another example involving an array of dictionaries, see Objective-C Is Still C (Not Java!)

Sort Array of CGPoints

I am trying to figure out what the fastest/cleanest way to sort an array of CGPoints would be. I think I could achieve this using loops but that might not be the fastest and I hope it isn't the cleanest way. I would like to take an array of random CGPoints and sort them say by smallest x coordinate to largest, or smallest x and y coordinate to largest.
After the correct comment by Chuck, I've updated the answer using the sortUsingComparator method:
Here is the complete code with sample data:
First we generate 100 random values that we enter to the Array:
NSMutableArray *testArray = [[NSMutableArray alloc] initWithCapacity:100];
for (int i=0; i<100; i++) {
CGPoint testPoint = CGPointMake(arc4random()%100, arc4random()%100);
[testArray addObject:[NSValue valueWithCGPoint:testPoint]];
}
and here is the actual code to sort the array:
[testArray sortUsingComparator:^(id firstObject, id secondObject) {
CGPoint firstPoint = [firstObject CGPointValue];
CGPoint secondPoint = [secondObject CGPointValue];
return firstPoint.x>secondPoint.x;
}];
finally we can verify that the array was sorted, by printing it:
NSLog(#"%#",testArray);
The C qsort() function is probably your best bet if you just have a plain array of CGPoints. Something like this:
int compareXCoords(CGPoint *a, CGPoint *b) {
return b->x - a->x;
}
// Later:
CGPoint points[100];
// initialize points somehow
qsort(points, 100, sizeof(CGPoint), compareXCoords);
// points is now sorted by the points' x coordinates
According to my comment, it's a good solution insert them on a NSMutableArray keeping the sort you decide.
You have to do something like this:
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:1];
CGPoint candidate;
// Look for the position it has to be
int 0;
for (CGPoint point in array) {
i++;
// Compare candidate with current point
// You have to define this condition, when point is greater than candidate
if (point > candidate) {
break;
}
}
[array insertObjectAtIndex:i-1];
Maybe my code has some errors, I can't check if it's correct now.

Getting x, y coordinate for objects in an array

i have a UIImageView object that i'm trying to get x coordinate of. I do this with code below
endingPoint.x = myObject.center.x;
Now, how can i do this if i have the same UIImageView inside of an array that i'm trying to loop through and get each object's x coordinate, some thing like below?
endingPoint.x = [posArray objectAtIndex:i].center.x;
I know it's a newbie question but i'm just starting with iOS.
You're very close. objectAtIndex: however, returns objects of type id (a generic pointer to anything), so you may not call .center (property) on it.
You must send it a message using the brackets symbols like this:
endingPoint.x = [[posArray objectAtIndex:i] center].x;
or cast the value to (UIImageView *) first:
endingPoint.x = ((UIImageView *)[posArray objectAtIndex:i]).center.x;
This would be done inside a for loop obviously.
You can do it either in an Objective-C fast enumeration loop or in a standard for loop.
Fast enumeration loop would look something like this.
for (UIImageView *image in posArray) {
endingPoint.x = image.center.x;
// Do everything else you want to do with the UIImageView inside the array.
}
This inside a loop should work:
endingPoint.x = [[posArray objectAtIndex:i] center].x;
try
endingPoint.x = [[posArray objectAtIndex:i] center].x;
or
endingPoint.x = ((UIImageView *)[posArray objectAtIndex:i]).center.x;

Using CGPoints in an NSArray

I have been trying to create an array stating the location of a UIImageView in an app I've been working on. What I am trying to do is by using an array I can store the location of my "player" image by using its x,y and z coordinates. The script I am trying to accomplish would look like
NSArray *location[3];
-(IBAction)startup;{
[location addObject: player.center.x];
[location addObject: player.center.y];
[location addObject: playerheight];
}
So I will be able to access this array to move my "player" on the screen in "3-dimensions", but I don't know how to convert the CGpoint values to NSValues so they can be used in the array, is there a simple way to do this inside of the array?
To convert floating point values to objects, use NSNumber. NSValue has wrappers for geometric types like CGPoint. Either would work for you.
[NSValue valueWithCGPoint:player.center];
[NSNumber numberWithFloat:player.center.x];
[NSNumber numberWithFloat:player.center.y];
To addition for the first answer.
When you'll need to read CGPoint back from your array, you can use something like that:
CGPoint point = [(NSValue *)[pointsArray objectAtIndex:i] CGPointValue];
Also note that there's no addObject method for NSArray (you can't add objects to an NSArray after its been created); you want NSMutableArray.
Instead of:
NSArray *location[3];
you probably want something more like:
NSMutableArray *location = [NSMutableArray arrayWithCapacity:3];
Does it have to be an NSArray? Why not use an array of structs?
typedef struct {
CGPoint location;
CGFloat height;
} PlayerLocation;
PlayerLocation players[3];
players[0].location = player.center;
players[0].height = playerheight;
Or depending on your design it may make more sense to declare an objective-C class that contains the x,y,z coordinates as ivars and store those objects into an NSArray.
#interface PlayerLocation : NSObject {
CGPoint location;
CGFloat height;
}
#end