Store an array of NSObject Pointers in C array - objective-c

I'd like to create an NSObject subclass that contains a few member vars:
#interface PointMass : NSObject
{
CGPoint mCurPosition;
CGPoint mLastPosition;
CGPoint mAcceleration;
}
-(id) initWithPosition:(CGPoint*) pos;
#import "PointMass.h"
#implementation PointMass
-(id) initWithPosition:(CGPoint*)pos
{
mCurPosition = *pos;
mLastPosition = *pos;
mAcceleration = ccp(0,0);
return self;
}
#end
And I would like to create a C-style array to hold a bunch of them within a cocos2d class:
// mNumPoint declared in interface, I've set it to 100
PointMass *pointMassList;
pointMassList = malloc(sizeof(PointMass*) * mNumPointMass);
for (int = 0; i < mNumPointMass; i++)
{
CGPoint point = ccp(100,100);
PointMass *p = [[PointMass alloc] initWithPosition: &point];
pointMassList[i] = p;
}
But I get an error
Expected method to write array element not found on object of type 'PointMass *'
Do I need to tell the compiler more about my PointMass Object if I want to store pointers to it in a C array?
I'm basically trying to have a play around with some particle math on iPhone without needing to unpack points from an NSArray constantly if it isn't clear what I'm trying to achieve here.
If I've gone about this in a backwards way I'd love to be corrected - it has been a while since I wrote vanilla C and I'm a little rusty!

it has been a while since I wrote vanilla C
You should still be able to make the distinction between a pointer-to-T and a pointer-to-pointer-to-T (T being PointMass in this case). You want to store an array of PointMass *, and not an array of PointMass (which you couldn't do anyway). So change the declaration of pointMassList to
PointMass **pointMassList;
and it will work. However, if you're using Objective-C anyway, why don't you simply store the instances into an NSArray?

Related

Setting values in a custom struct as property in Objective-C [duplicate]

This question already has answers here:
Mixing C Structs and Objective-C Properties
(2 answers)
Closed 8 years ago.
I have class A with a header that looks something like this:
typedef struct {
int x;
int y;
} Position;
#interface ClassA : NSObject
#property Position currentPosition;
#end
And I try to assign individual values of the position struct from the property in another class like this:
ClassA * classA = [ClassA new];
classA.currentPosition.x = 10;
Which gives an error "expression is not assignable" and won't compile.
I can set it like this:
ClassA * classA = [ClassA new];
Position position = {
.x = 1,
.y = 2
};
classA.currentPosition = position;
And I can even alter individual "properties" of position variable like this:
ClassA * classA = [ClassA new];
Position position = {
.x = 1,
.y = 2
};
// WORKS
position.x = 4;
// DOESN'T WORK
// classA.currentPosition.x = 4;
classA.currentPosition = position;
Why can't I set values individually when they are a property?
This expression:
classA.currentPosition
returns a temporary copy of your struct, not the struct itself. The compiler error is telling you that you can't assign a value to some member of that temporary copy (because it's an rvalue, technically). But you don't want to assign a value to that member anyway, because it would just disappear along with the struct itself.
So why are you only getting a copy of the struct in the first place?
Because
#property Position currentPosition
is actually just shorthand for:
-(Position)currentPosition;
-(void)setCurrentPosition(Position value);
and in C-family languages, the first line (the getter) indicates that it's returning a Position struct by-value, or as a copy.
You could make your own accessor that returns a reference, but you probably shouldn't. This isn't a common idiom in Objective-C -- at least not in this context -- and you should generally try to stick with common idioms for a language.
Instead, you should use position like the following;
Position pos = classA.position;
pos.x = 4;
classA.position = pos;
Lastly, if you really want to be able to set currentPosition using the syntax you originally desired, while maintaing Objective-C idioms, you could just make Position a class rather than a struct. Then, the property can return a Position * and the rest of the syntax would work. Make sure to initialize the pointer in your init function (or when appropriate).
Properties don't work for C structs.
You can do it like:
#property Position *currentPosition;
Basically, using a pointer.
Now you actually need to initialize that pointer so:
- (id) init {
self = [super init];
if(self){
self.currentPosition = malloc(sizeof(Position));
}
return self;
}
Then, don't forget to use arrow notation, since you're dealing with a pointer:
classA.currentPosition->x = 5;
And don't forget to free the memory you requested!
-(void)dealloc{
free(self.currentPosition);
}

'Assigning to 'id' from incompatible type'

I'm implementing a objective C wrapper for Box2d (which is written in c++). The b2Body keeps a reference to its wrapper B2Body in its userData field. GetUserData returns a void*. I'm now implementing fast iteration for getting the B2Bodies out of the B2World.
I get an 'Assigning to 'id' from incompatible type 'B2Body *' error at the line indicated below. Why?
#import "B2Body.h"
#import "B2World.h"
#import "Box2d.h"
#implementation B2World
-(id) initWithGravity:(struct B2Vec2) g
{
if (self = [super init])
{
b2Vec2 *gPrim = (b2Vec2*)&g;
_world = new b2World(*gPrim);
}
return self;
}
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len;
{
if(state->state == 0)
{
state->mutationsPtr = (unsigned long *)self;
state->extra[0] = (long) ((b2World*)_world)->GetBodyList();
state->state = 1;
}
// pull the box2d body out of extra[0]
b2Body *b = (b2Body*)state->extra[0];
// if it's nil then we're done enumerating, return 0 to end
if(b == nil)
{
return nil;
}
// otherwise, point itemsPtr at the node's value
state->itemsPtr = ((B2Body*)b->GetUserData()); // ERROR
state->extra[0] = (long)b->GetNext();
// we're returning exactly one item
return 1;
}
`
B2Body.h looks like this:
#import
#interface B2Body : NSObject
{
int f;
}
-(id) init;
#end
NSFastEnumerationState is a C structure, and the itemsPtr field is:
id __unsafe_unretained *itemsPtr;
In earlier versions, the __unsafe_unretained specifier was obviously missing.
Note, that the field itemsPtr is a pointer-to-id. Since id is essentially a pointer, itemsPtr is a pointer to an object pointer. Actually, this field is what holds the array of objects that allows the fast enumeration. Basically, it trolls through this array of object pointers.
Since I know nothing about Box2d, that's about all I can say. Assuming b->GetUserData() returns a pointer to an array of objects, you should be able to do this:
state->itemsPtr = (__unsafe_unretained id *)b->GetUserData();
While a bit dated, Mike Ash's article is still a great source for implementing fast enumeration.
EDIT
Just noticed that you are returning a single object. So, I assume GetUserData just returns a single object pointer. Since you need to return a pointer to object pointers, you would need to do something like this:
id object = (__bridge id)b->GetUserData();
state->itemsPtr = &object;
However, that stack object will be gone once you return from this method, which is why you are passed a stack buffer you can use. Thus, you should probably stuff that single pointer into the provided stack buffer:
*buffer = (__bridge id)b->GetUserData()
state->itemsPtr = buffer;

Create an global array containing floating numbers

I wanted to create 2 global arrays which can be updated during the run of the programme.In each update i add one element to zeroth position and deleted the last number
I created the arrays as....
In the .h file..........
//////////////
#interface Shared : NSObject{
NSMutableArray *x;
NSMutableArray *y;
}
#property (nonatomic,retain) NSMutableArray *x;
#property (nonatomic,retain) NSMutableArray *y;
+(Shared*)sharedInstance;
#end
In .m file
staticShared* sharedInstance;
#implementation Shared
#synthesize x;
#synthesize y;
+(Shared*)sharedInstance
{
if (!sharedInstance) {
sharedInstance=[[Sharedalloc]init];
}
returnsharedInstance;
}
-(Shared*)init
{
self = [superinit];
if(self)
{
x=[[NSMutableArrayalloc] init];
x=[NSMutableArrayarrayWithObjects:#"0",#"0",#"0",#"0",#"0",#"0",#"0",nil];
y=[[NSMutableArrayalloc] init];
y=[NSMutableArrayarrayWithObjects:#"0",#"0",#"0",#"0",#"0",#"0",nil];
}
returnself;
}
#end
Then i used to call them and re,ove and added elements using the following code....
[[shared sharedInstance].y removeLastObject];
[[shared sharedInstance].y insertObject:new_element atIndex:0];
[[shared sharedInstance].x removeLastObject];
[[shared sharedInstance].x insertObject:new_element atIndex:0];
In the mean time i call these values and calculate an arithmetic value using an expression.
This seems to work well. But it seems to be an inefficient way to handle floating point numbers which i store in it. As these arrays creates objects. Is there any easy method that i can create a global array containing specified amount of floating point numbers and update it during the run of the programm(array size is fixed) by deleting the last object, and call them back to do calculation?
Please help me!
EDIT 1
To sir deanWombourne
.................................
I implement as you instructed! Can you please go through this and help me to correct 2 errors i get.
IN the .h file
#interface Shared : NSObject{
#private
float input[7];
float output[6];
}
+(Shared*)sharedInstance;
-(void)addNewInput:(float)input1;
-(float *)input;
-(void)addNewOutput:(float)output1;
-(float *)output;
#end
in .m file............
#implementation Shared
-(id)init{
if((self =[superinit])){
for(int n=0; n<7 ;++n)
input[n]=0.00f;
for(int n=0; n<6 ;++n)
output[n]=0.00f;
}
returnself;
}
-(void)addNewInput:(float)input1{
input[0]=input[1];
input[1]=input[2];
input[2]=input[3];
input[3]=input[4];
input[4]=input[5];
input[5]=input[6];
input[6]=input1;
}
-(float *)input {
returninput;
}
-(void)addNewOutput:(float)output1{
output[0]=output[1];
output[1]=output[2];
output[2]=output[3];
output[3]=output[4];
output[4]=output[5];
input[5]=output1;
}
-(float *)output {
returnoutput;
}
#end
When calling it
float reading= (accel_reading)/(1.165969038*1e5f);
[[SharedsharedInstance] addNewInput:reading];
Problems i get
1. In the implementation, it says incomplete implementation (it's a warning not an error)
2. How can i used a for loop to fill array values or is this way ok?
Major problem i get,
When i call it as shown above, program stops running telling
Terminating application due to uncaught exception 'NSInvalidArgumentException', reason '+[SharedsharedInstance]: unrecognized selector sent to class 0x5780'
Please help me through this...............
Your code Smells (and I mean that in the nicest possible way!)
Using two parallel arrays and keeping in sync is a bad design pattern (and a performance hit in quite a few ways!). Especially as there is already a struct that handles storing an x and y at the same time - CGPoint).
You're solving the 'only objects go in arrays' problem by converting your float' primitives toNSString` objects, which is horrendously inefficient - take a look instead at the NSValue class, it's designed to put native C primitives into an object without expensive parsing operations :)
You might also want to look into malloc (and free etc) and deal with the whole problem at the C level - this will mean no objects at all and would be blindingly fast (at the cost of more complicated code).
Hope this helps, if you have any questions just add a comment to this answer :)
EDIT
If all you want to do is store 4 x and y values, then this is probably the easiest way to do it :
#interface Shared : NSObject {
#private
CGPoint points[4];
}
+(Shared *)sharedInstance;
- (void)addNewPoint:(CGPoint)point;
- (CGPoint *)points;
#end
#implementation
- (id)init {
if ((self = [super init])) {
// Start with 0,0 for all your points
for (int n = 0; n < 4; ++n)
points[n] = CGPointZero;
}
return self;
}
- (void)addNewPoint:(CGPoint)point {
// Just move all the points along one and add the new one to the end
// (yes, this could be done in a loop but there's not that much point for 4 points!)
points[0] = points[1];
points[1] = points[2];
points[2] = points[3];
points[3] = point;
}
- (CGPoint *)points {
return points;
}
#end
This gives you a method addNewPoint that removes the first point and adds the new point to the end of your array.
You also get the method points that returns the 4 points. Use it something like :
// To add a point
CGPoint newPoint = CGPointMake(100, 100);
[[Shared sharedInstance] addNewPoint:newPoint];
// To do something with the points (in this case, NSLog them)
CGPoint *points = [[Shared sharedInstance] points];
for (int n = 0; n < 4; ++n)
NSLog(#" Point %i : %#", n, NSStringFromCGPoint(points[n]));
EDIT #2
From your comments, you need two arrays, one with input data and one with output data. Try something like this :
#interface Shared : NSObject {
float inputs[4];
float outputs[5];
}
...
This will give you two arrays to read/write to - one called inputs and the other called outputs. Access them in pretty much the same way you did the ones in my first edit :
float *inputs = [[Shared sharedInstance] inputs];
for (int n = 0; n < 4; ++n)
NSLog(#" Input %i : %f", n, inputs[n]);
float *outputs = [[Shared sharedInstance] outputs];
for (int n = 0; n < 5; ++n)
NSLog(#" Output %i : %f", n, output[n]);
Would a linked list be overkill for what you're trying to achieve? It's not quite as simple as a static array of floats, but makes the removal of the last object and insertion of the zeroth object reasonably simple and fast.
If you want an array containing a specific number of Objects, you can use NSArray, which is static, opposed to NSMutableArray.
As for the array being Global, just implement a singleton class that contains the 2 arrays and provides the associated methods.
in Globals.h:
#interface Globals : NSObject
+ (Globals *) sharedGlobals;
#end
in Globals.m:
#implementation Globals
static Globals *sharedGlobals = nil;
+ (Globals *) sharedGlobals{
#synchronized(self){
if (sharedGlobals == nil){
sharedGlobals = [[self alloc] init];
}
}
return sharedGlobals;
}
you then can access the arrays (after you implemented them) with the following line:
[[Globals sharedGlobals] getArrayX];
Here is a sketch to get you going.
Your array size is fixed and only contains floating point numbers, start with a C array:
double x[] = {0, 0, 0, 0, 0, 0, 0};
double y[] = {0, 0, 0, 0, 0, 0};
The number of elements in these arrays can be calculated rather than hard-coded:
int xCount = sizeof(x)/sizeof(double);
int yCount = sizeof(y)/sizeof(double);
Now use these arrays as a circular buffer, declare a cursor and initialise:
int xCursor = 0;
The item at the front of the queue is at the cursor:
valueAtFrontOfQueue = x[xCursor]; // get the current front item
To remove the value at front and add a new one to the rear replace the value at the cursor with the new value and increment the cursor:
x[xCursor] = newValueForBackOfQueue; // replace it with new item for back of queue
xCursor = (xCursor + 1) % xCount; // and advance cursor using mod arithmetic to it cycles around
No wrapping doubles as objects, no dynamic allocation at all.
Wrap the above up as you see fit, maybe as a class, and you're done.

Objective-C accessing float getters with variable names

Let's say I have an NSArray called myArray of NSStrings (#"a0",#"a1",#"a2")
Then in a fast enumeration I loop into my array to build properties according to that NSStrings. I've got a problem accessing that properties.
I'm trying something like that :
#property (nonatomic) float a0propertyLow;
#property (nonatomic) float a0propertyHigh;
#property (nonatomic) float a1propertyLow;
#property (nonatomic) float a1propertyHigh;
..
.. etc.
for (NSString *aPos in myArray) {
NSString *low = [NSString stringWithFormat:#"%#propertyLow",aPos];
NSString *high = [NSString stringWithFormat:#"%#propertyHigh",aPos];
SEL lowSel = NSSelectorFromString(low);
SEL highSel = NSSelectorFromString(high);
if ([self respondsToSelector:lowSel]&&[self respondsToSelector:highSel]) {
id sumPartOne = [self performSelector:lowSel];
id sumPartTwo = [self performSelector:highSel];
float bla = (float)sumPartOne + (float)sumPartTwo;
}
}
I know my code is wrong but I don't know how to make it work.
My problem is that lowSel and highSel are getters which returns float but the perform selector method returns id which is ok for an object but not for floats.
So, how can I access my float getters with variable names ? I'm sure answer must be simple but it seems that my mind is looking for something complicated (and which obviously doesn't work) so I'm asking for help :)
Thank you very much for your help
You can't use performSelector: to call a method that returns a scalar value. The documentation for performSelector: clearly says what you have to do:
For methods that return anything other than an object, use NSInvocation.
An NSInvocation is a little more complex to set up but more flexible regarding arguments and return types.
In your case, it is probably easier to use Key-Value Coding instead:
[self valueForKey:low];
takes the return type into account and will automatically wrap the float in an NSNumber.
If you really need to use these getter methods, you can change your properties to double and use objc_msgSend_fpret():
#include <objc/runtime.h>
#include <objc/message.h>
double arg0 = objc_msgSend_fpret(self, lowSel);
If you can avoid getters (I know, that's not good practice, but anyway, it works for sure with the following method), and use the instance variables directly:
void *object_getIvarPtr(id obj, const char *name)
{
if (!obj || !name)
{
return NULL;
}
Ivar ivar = object_getInstanceVariable(obj, name, NULL);
if (!ivar)
{
return NULL;
}
return ((char *)obj + ivar_getOffset(ivar));
}
float arg0 = *(float *)object_getIvarPtr(self, [lowSel UTF8String]);
Hope this helps.
One way you can do is convert your floats into objects at runtime such as:-
NSString *str=[NSSTring stringWithFormat:#"%f",yourFloatValue];
and then u can retrive it using
[str floatValue];

Fast way to store and retrieve pairs of numbers in Objective-C

I am implementing queued flood fill algorithm and need to store and retrieve pairs of numbers in NSMutableArray.
Basically, I am creating an array
m_queue = [NSMutableArray array];
then at some time I populate the array
[m_queue addObject:[NSValue valueWithCGPoint:CGPointMake(x + 1, y)]];
then I retrieve data for the next iteration and remove the value at the beginning of the array
NSValue* value = [m_queue objectAtIndex:0];
[m_queue removeObjectAtIndex:0];
CGPoint nextPoint = [value CGPointValue];
[self queueFloodFill8:nextPoint.x y:nextPoint.y];
The question is: what can I do to avoid creating large number of CGPoint and NSValue objects?
I don't really need points, the algorithm uses pairs of integer values, so I think there might be a better way to store such pairs.
UPDATE:
I looked into implementing C-style solution like #mattjgalloway and #CRD suggested.
I've introduced
typedef struct lookup_point_struct
{
int x;
int y;
struct lookup_point_struct* next;
} LookupPoint;
and have rewritten code to use linked list of such structs instead of NSMutableArray and CGPoint/NSValue.
All this made my code about 3 times faster. And memory consumption dropped significantly too.
There wouldn't really be a better Objective-C / Foundation way of doing it, apart from maybe creating your own class such as NumberPair or something which you put into the array rather than using NSValue and CGPoint. It might be slightly more memory efficient to do that and you could make NumberPair contain two integers rather than floats like you are concerned about. Something like:
#interface NumberPair : NSObject
#property (nonatomic, assign) int x;
#property (nonatomic, assign) int y;
#end
#implementation NumberPair
#synthesize x, y;
#end
...
m_queue = [NSMutableArray array];
NumberPair *newPair = [[NumberPair alloc] init];
newPair.x = 1;
newPair.y = 2;
[m_queue addObject:newPair];
...
NumberPair *nextPoint = [m_queue objectAtIndex:0];
[m_queue removeObjectAtIndex:0];
[self queueFloodFill8:nextPoint.x y:nextPoint.y];
Other than that you could do a more C-like thing of having a struct containing two integers, create a dynamically allocated array to store the structs (you'd need to know the max size of the queue or keep reallocating). Something like:
typedef struct {
int x;
int y;
} NumberPair;
NumberPair *m_queue = (NumberPair*)malloc(sizeof(NumberPair) * QUEUE_SIZE);
// ... etc
Also, you might want to check out my MJGStack class which wraps NSMutableArray to provide a stack like interface which you might be able to adjust slightly to do what you want rather than using NSMutableArray directly. Although that's not essential by any means.
How large do you expect your m_queue array to get?
If the cost of the NSMutableArray and NSValue objects (CGPoint is a struct, no real cost there) is impacting your algorithm then consider using a C-style array of structs as a circular buffer together with two indexes for front/back of the queue. You can abstract this into a queue class (or an adt using functions to save on dynamic method call overhead if you need to).
If you need to deal with an unbounded queue you can malloc & realloc the array with your queue class/adt as needed (which is essentially what NSMutableArray does behind the scenes but with more overhead for its generality).