Objective-c: Adding a custom object to a NSMutableArray - objective-c

I usually program in java or c++ and I recently started with objective-c. Looking for vectors in objective-c, I found NSMutableArray which seems to be the best option. I'm working on an opengl game and I'm trying to create an NSMutableArray of textured quads for my sprites. Here is the relevant code:
I define textured quads:
typedef struct {
CGPoint geometryVertex;
CGPoint textureVertex;
} TexturedVertex;
typedef struct {
TexturedVertex bl;
TexturedVertex br;
TexturedVertex tl;
TexturedVertex tr;
} TexturedQuad;
I create an array in the interface:
#interface Sprite() {
NSMutableArray *quads;
}
I initiate the array and I create the texturedQuads based on "width" and "height", which are the dimensions of a single sprite, and "self.textureInfo.width" and "self.textureInfo.height", which are the dimensions of the entire sprite sheet:
quads = [NSMutableArray arrayWithCapacity:1];
for(int x = 0; x < self.textureInfo.width/width; x++) {
for(int y = 0; y < self.textureInfo.height/height; y++) {
TexturedQuad q;
q.bl.geometryVertex = CGPointMake(0, 0);
q.br.geometryVertex = CGPointMake(width, 0);
q.tl.geometryVertex = CGPointMake(0, height);
q.tr.geometryVertex = CGPointMake(width, height);
int x0 = (x*width)/self.textureInfo.width;
int x1 = (x*width + width)/self.textureInfo.width;
int y0 = (y*height)/self.textureInfo.height;
int y1 = (y*height + height)/self.textureInfo.height;
q.bl.textureVertex = CGPointMake(x0, y0);
q.br.textureVertex = CGPointMake(x1, y0);
q.tl.textureVertex = CGPointMake(x0, y1);
q.tr.textureVertex = CGPointMake(x1, y1);
//add q to quads
}
}
The problem is I don't know how to add the quad "q" to the array "quads". Simple writing [quads addObject:q] doesn't work because the parameter should be an id not a TexturedQuad. I've seen examples of how to make an id from an int etc, but I don't know how to do it with an object like my TexturedQuad.

The essence of it is that you wrap your C struct in an Obj-C class. The Obj-C class to use is NSValue.
// assume ImaginaryNumber defined:
typedef struct {
float real;
float imaginary;
} ImaginaryNumber;
ImaginaryNumber miNumber;
miNumber.real = 1.1;
miNumber.imaginary = 1.41;
// encode using the type name
NSValue *miValue = [NSValue value: &miNumber withObjCType:#encode(ImaginaryNumber)];
ImaginaryNumber miNumber2;
[miValue getValue:&miNumber2];
See here for more information.
As #Bersaelor pointed out, if you need better performance use pure C or switch to Obj-C++ and use vectors instead of Obj-C objects.

An NSMutableArray takes any NSObject* but not just structs.
If you're serious about programming in Objective-C, take a look at some tutorials.
Furthermore, NSMutableArrays are meant for convenience, if your adding/deleting a lot of objects to that Array, use plain C-stacks.
Especially for your use-case that more low-level approach will get better performance.
Keep in mind, Objective-C(++) is just a superset of C(++), so you can use any C(++) code you are already familiar with.
When I wrote my game tactica for iOS, I switched to C-Code whenever I had to do heavy lifting (i.e. recursive AI-functions that get called hundreds of times per second).

Related

Properly declare 2D array of Ints [duplicate]

I have the following code which works fine...
int testarr[3][3] = {
{1,1,1},
{1,0,1},
{1,1,1}
};
[self testCall: testarr];
Which calls this function:
- (void)testCall: (int[3][3]) arr {
NSLog(#"cell value is %u",arr[1][1]);
}
I need the array to be of variable length - What is the best way to declare the function?
Using blanks doesn't work:
- (void)testCall: (int[][]) arr {
Thanks for your help.
I would write this as:
- (void) testCall: (int *) aMatrice;
Doing so allows you to avoid multiple mallocs and the math to calculate a single offset in a linear array based on x, y coordinates in a 2D array is trivial. It also avoids the multiple mallocs implied by int** and the limitations of 2D array syntax perpetuated by the language.
So, if you wanted a 4x5 array, you might do:
#define WIDTH 4
#define HEIGHT 5
#define INDEXOF(x,y) ((y*WIDTH) + x)
int *myArray = malloc(sizeof(int) * 5 * ELEMS_PER_ROW);
You could then initialize the array linearly or with a nested for loop:
for(int x=0; x<width; x++)
for(int y=0; y<height; y++)
myArray[INDEXOF(x,y)] = ... some value ...;
And you would pass it to the method like:
[foo testCall: myArray];
Though you might want to also carry along the width and the height or, better yet, create a IntMatrix subclass of NSObject that wraps all of the pointer arithmetic and storage beyond a nice clean API.
(all code typed into SO)
C arrays can't be variable in more than one dimension.
You can't have this:
int testarr[][] = {
{1,1,1},
{1,0,1,2},
{1,1}
};
But you can have this:
int testarr[][3] = {
{1,1,1},
{1,0,1},
{1,1,1},
{4,5,6},
{7,8,9}
}
foo(testarr);
void foo(int param[][3])
{
printf("%d", param[3][1]); // prints 5
}
You can't use int[][] because the size of the second dimension affects how the array is laid out in memory. If you know the second dimension you can use int[][x], otherwise you'll have to use int** which can be accessed just like an array.
Why don't you just use NSArray or NSMutableArray with NSIntegers? Those array classes are of variable length, and much easier to use.
This would result in
- (void)testCall: (NSArray *) arr {
NSLog(#"cell value is %u", [[arr objectAtIndex:1] objectAtIndex:1]);
}
(Of course, you would also have to define testarr using NSArray.)
If you really want to use C arrays, making the method argument a pointer to an int with
- (void)testCall: (int*) arr {
will probably work (with the rest of the code staying the same).
call
int testarr[3][3] = {
{1,1,1},
{1,0,1},
{1,1,1}
};
[self testCall: (int *)testarr];
function
- (void)testCall: (int *) arr
{
int (*V_arr)[3] = (int(*)[3])arr;
NSLog(#"cell value is %u",V_arr[1][1]);
}

How to declare C style arrays in objective-c app?

I have two NSArrays, one of CLLocation and one of doubles (encased in objects) that I need to write to C vectors to draw a gradient MKPolyline as defined here (https://github.com/wdanxna/GradientPolyline). I tried to copy some of the code I saw there in preparation to call one of its functions:
points = malloc(sizeof(CLLocationCoordinate2D)*self.run.locations.array.count);
velocity = malloc(sizeof(float)*self.run.locations.array.count);
for(int i = 0; i<self.run.locations.array.count; i++){
points[i] = self.run.locations.array[i];
velocity[i] = [velocities[i] floatValue];
}
Here self.run.locations.array is an array of CLLocations.
Right now I can't even build the project because I have not declared the variables. But where/how do I declare these variables? I don't know C, and the project I am trying to use doesn't seem to include these declarations in a place I can find them.
points is an array of CLLocationCoordinate2D (dynamically allocated) so it should be a pointer to CLLocationCoordinate2D i.e.
CLLocationCoordinate2D *points;
velocity is an array of float so it should be declared as
float *velocity;
Alternatively you can do this
float velocity[];
if you prefer array syntax.

2D Array Declaration - Objective C

Is there a way to declare a 2D array of integers in two steps? I am having an issue with scope. This is what I am trying to do:
//I know Java, so this is an example of what I am trying to replicate:
int Array[][];
Array = new int[10][10];
Now, in OBJ-C I want to do something similar, but I cant get the syntax right. Right now I have it in one step, but I cannot use it outside of the If-Statement in which I currently have it:
int Array[10][10]; //This is based on an example I found online, but I need
//to define the size on a seperate line than the allocation
Can anyone help me out with this? I know its probably a more basic question, but you can't use the keyword "new" outside of a message (to my knowledge) and you cant send messages to ints. :(
*EDIT 1:**
My problem is scope related.
//Declare Array Somehow
Array[][] //i know this isn't valid, but I need it without size
//if statement
if(condition)
Array[1][2]
else
Array[3][4]
//I need to access it outside of those IFs
//... later in code
Array[0][0] = 5;
This is my preferred way of creating a 2D array, if you know the size of one of the boundaries:
int (*myArray)[dim2];
myArray = calloc(dim1, sizeof(*myArray));
And it can be freed in one call:
free(myArray);
Unfortunately, one of the bounds MUST be fixed for this to work.
However, if you don't know either of the boundaries, this should work too:
static inline int **create2dArray(int w, int h)
{
size_t size = sizeof(int) * 2 + w * sizeof(int *);
int **arr = malloc(size);
int *sizes = (int *) arr;
sizes[0] = w;
sizes[1] = h;
arr = (int **) (sizes + 2);
for (int i = 0; i < w; i++)
{
arr[i] = calloc(h, sizeof(**arr));
}
return arr;
}
static inline void free2dArray(int **arr)
{
int *sizes = (int *) arr;
int w = sizes[-2];
int h = sizes[-1];
for (int i = 0; i < w; i++)
free(arr[i]);
free(&sizes[-2]);
}
The declaration you showed (e.g. int Array[10][10];) is OK, and will be valid for the scope it was declared to, if you do it in a class scope, then it will be valid for the whole class.
If the size of the array varies, either use dynamic allocation (e.g. malloc and friends) or use NSMutableArray (for non-primitive data types)

Returning a 2D C array of type id in Objective-C

I'm using a 2D C array of ids in my iOS app. Is it possible to return this in an objective-C method? As an alternative solution, I tried to return a pointer to a 2D C array of integers, but I cannot modify the 2D-int array.
- (int (*)[8][8])board:(Piece *)piece
{
int (*layout)[8][8] = malloc(8 * 8 * sizeof(int));
//Cannot modify layout 2D C array
return layout;
}
I have some experience in Objective-C, but none in C. Am I likely to continually run into problems using C 2D arrays, such that I should make a 2D-Array Objective-C class? What is the more typical approach an iOS developer would use?
- (int **)board:(Piece *)piece
{
int **layout = malloc(8 * sizeof(int *));
for(int i=0; i<8; i++)
layout[i] = malloc(8 * sizeof(int));
return layout;
}
Don't forget to free the memory in the end. Also, you could also use a one dimensional array and something like this to access it in a similar way:
#define access(array, x, y) array[y * 8 + x]
There is also now drop in multi-dimensional array class in Objective-C, but you could create a NSArray with other NSArray's inside of it, or, google if someone else did this (I remember at least one implementation but can't recall its name)
After you declare int (*layout)[8][8] = malloc(8 * 8 * sizeof(int));, You can change the values like (*layout)[x][y]=val;. But I recommend you to declare int (*layout)[8], so you can access elements by simply layout[x][y]=val.
Edit: I don't know about Objective-C, but in C, the function I suggested will look like:
int (*newarray())[8] {
int (*l)[8]=malloc(64*sizeof(int));
// You can do stuff like l[2][4]=15 here
return l;
}

Am I using Objective-C collections properly here?

I'm attempting to write an iPhone game. This function is intended to apply gravitational force to several objects. I'm porting it from Python and I'm wondering if my use of dictionaries and arrays as tuples makes sense and is typical/idiomatic in Objective C. Any comments on the code appreciated.
+ (void)updateBodies:(NSMutableArray*)bodies {
NSMutableDictionary* totals = [NSMutableDictionary dictionaryWithCapacity:[bodies count]];
for (Body* body in bodies) {
if (body.fixed) {
continue;
}
float tx;
float ty;
for (Body* other in bodies) {
if (other == body) {
continue;
}
float dx = other.x - body.x;
float dy = other.y - body.y;
float dist2 = pow(dx, 2) + pow(dy, 2);
float dist = sqrt(dist2);
float mass = pow(other.radius, 3);
float magnitude = G * mass / dist2;
float ux = dx / dist;
float uy = dy / dist;
tx += ux * magnitude;
ty += uy * magnitude;
}
NSNumber* ntx = [NSNumber numberWithFloat:tx];
NSNumber* nty = [NSNumber numberWithFloat:ty];
NSArray* tuple = [NSArray arrayWithObjects:ntx, nty, nil];
[totals setObject:tuple forKey:body];
}
for (Body* body in [totals allKeys]) {
NSArray* tuple = [totals objectForKey:body];
float tx = [[tuple objectAtIndex:0] floatValue];
float ty = [[tuple objectAtIndex:1] floatValue];
body.dx += tx;
body.dy += ty;
}
}
The only problem you should be aware of is that NSDictionary copies its keys. So Body needs to implement NSCopying and the instances of Body in totals are not necessarily the same instances in the passed in bodies array depending on how you implement NSCopying.
The approach I would use would be to consider velocity as a property of the body. That way you don't need a dictionary to associate the body to its velocity, you can just iterate through the array itself.
Talking of iterating. You can halve the number of iterations and some calculations by calculating the velocity of the other body at the same time as the first body. i.e. your inner loop would only iterate through the bodies that come after the outer loop body in the array.
It would mean you can't use fast iteration, so you'd have to profile to figure out which approach is faster.
On a minor note, I think
for ....
{
if (!condition)
{
continue;
}
// do stuff
}
is really ugly. What's wrong with:
for ....
{
if (condition)
{
// do stuff
}
}
You could used block enumeration for final update:
[totals enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
Body* body = key;
NSArray* tuple = key;
body.dx += [[tuple objectAtIndex:0] floatValue];
body.dy += [[tuple objectAtIndex:1] floatValue];
}];
An other solution could be to not used NSDictionary and NSArray and use a C array. It should be faster than using (and create) objects.