std::vector in objective c method
Asked Answered
B

4

6

Im working in objective C++. The issue I am stuck with is that I need to pass a std::vector to an objective c method. Is this possible? Below is my current code where I am having to do my calculations on the vector in the vector definition method (adding an offset value to the members of the array) before passing to the method as a C array. Ideally I would like to set the offset values in the second method, thus splitting up the definition (there will be several of these) The offset will be variable unlike in the example below.

So instead of passing in (b2Vec2 *)vect i want to use vectors

- (void)createterrain1 {

using namespace std;
vector<b2Vec2>vecVerts;
vector<int>::size_type i;
vecVerts.push_back(b2Vec2(-1022.5f / 100.0, -20.2f / 100.0));
vecVerts.push_back(b2Vec2(-966.6f / 100.0, -18.0f / 100.0));
vecVerts.push_back(b2Vec2(-893.8f / 100.0, -10.3f / 100.0));
vecVerts.push_back(b2Vec2(-888.8f / 100.0, 1.1f / 100.0));
vecVerts.push_back(b2Vec2(-804.0f / 100.0, 10.3f / 100.0));
vecVerts.push_back(b2Vec2(-799.7f / 100.0, 5.3f / 100.0));
vecVerts.push_back(b2Vec2(-795.5f / 100.0, 8.1f / 100.0));
vecVerts.push_back(b2Vec2(-755.2f/ 100.0, -9.5f / 100.0));
vecVerts.push_back(b2Vec2(-632.2f / 100.0, 5.3f / 100.0));
vecVerts.push_back(b2Vec2(-603.9f / 100.0, 17.3f / 100.0));
vecVerts.push_back(b2Vec2(-536.0f / 100.0, 18.0f / 100.0));
vecVerts.push_back(b2Vec2(-518.3f / 100.0, 28.6f / 100.0));
vecVerts.push_back(b2Vec2(-282.1f / 100.0, 13.1f / 100.0));
vecVerts.push_back(b2Vec2(-258.1f / 100.0, 27.2f / 100.0));
vecVerts.push_back(b2Vec2(-135.1f / 100.0, 18.7f / 100.0));
vecVerts.push_back(b2Vec2(9.2f / 100.0, -19.4f / 100.0));
vecVerts.push_back(b2Vec2(483.0f / 100.0, -18.7f / 100.0));
vecVerts.push_back(b2Vec2(578.4f / 100.0, 11.0f / 100.0));
vecVerts.push_back(b2Vec2(733.3f / 100.0, -7.4f / 100.0));
vecVerts.push_back(b2Vec2(827.3f / 100.0, -1.1f / 100.0));
vecVerts.push_back(b2Vec2(1006.9f / 100.0, -20.2f / 100.0));
vecVerts.push_back(b2Vec2(1023.2fdddddd / 100.0, -20.2f / 100.0));
i = vecVerts.size();


//I would like to pass this sets of calculations to the stitch method below rather
 than do it here

vector<b2Vec2>::iterator pos;

//add y offset value to our b2Vec2
for(pos = vecVerts.begin();pos != vecVerts.end();++pos)

{
    //get b2Vec2 value at index
    b2Vec2 currVert = *pos;

    //add y offset (this will come from the sprite image size latterly, set value for testing only
    b2Vec2 addVert = b2Vec2(currVert.x,currVert.y + 40 /PTM_RATIO); 

    //copy offset added b2Vec2 back to vector as index
    pos->b2Vec2::operator=(addVert);
}


 //currently using this as kludge to pass my vector to the stitch method
b2Vec2 * chain = &vecVerts[0];
[self stitchterrainvertswith:chain num:i];

This is my current method passing in my vector as a C styled array

-(void)stitchterrainvertswith:(b2Vec2 *)verts num:(int)num {


//create bodydef
b2BodyDef groundBodyDef;

//set body as static
groundBodyDef.type = b2_staticBody;

//set body position 
groundBodyDef.position.Set(0, 0);

//create body using def
groundBody = world->CreateBody(&groundBodyDef);

//create shapes

b2EdgeShape screenEdge;
b2ChainShape terrain;

terrain.CreateChain(verts, num);
  groundBody->CreateFixture(&terrain,0);

//keeps track of max x value for all the ground pieces that are added to the scene
   //maxVerts.x += totalXVerts.x;
    }

I tried using an objc wrapper for std::vector but got kind of lost here is my example:

VecWrap.h
#import "Box2D.h"
#include <vector>

struct VecAcc;

@interface VecWrap : NSObject
{
struct VecAcc* vec;
}
@end

VecWrap.MM

#import "VecWrap.h"

struct VecAcc {
std::vector<b2Vec2>data;
};


@implementation VecWrap


-(id)init 
{
    vec = 0;
    if (self == [super init]) {
    vec = new VecAcc;
}
   return self;
}

-(void)dealloc 

{
delete vec;
[super dealloc];
}
@end

and then created the following method:

-(void)stitchgroundvectswith:(VecAcc*)vecs num:(int)num;

Which doesn't work is this even possible?

Beggarweed answered 3/1, 2012 at 14:12 Comment(0)
U
7

All correct, and Barry Wark's solution works but I don't recommend it because language-specific pre-processor tricks like this are fragile IMO. In particular, they don't work correctly if there are namespaces involved, and only work on pointers.

First, I strongly recommend that developers keep their ObjC and C++ separate as much as possible and minimize ObjC++ to a few places where it's really needed. ObjC++ is a crazy language that gdb often has trouble with, hurts ARC performance, compiles slower, and generally is mostly a useful-at-times hack rather than a real language.

I recommend this approach to hiding your C++ methods from ObjC in headers:

@interface MyClass

- (void)anOtherMethodCalledFromObjC;

#ifdef __cplusplus
- (void)stitchGroundVectsWithVector:(std::vector<b2Vec2>)vec;
#endif
@end

But generally speaking, I recommend that most of your program be .m and .cpp files, with a few .mm files to glue them together.

For extensive discussion on how to do this in older code, see Wrapping C++-Take 2. Newer code doesn't require ivars to be in the headers, so it should be even simpler to implement today.

Urogenous answered 3/1, 2012 at 14:50 Comment(0)
T
3

You don't have to write wrappers. That's the purpose of Objective-C++: you can declare an Obj-C method to accept/return a C++ object and it will work. For example:

- (void)someMethod:(const std::vector<b2Vec2>&)vec {
    /* do something with vec in C++ code */
}
Turkic answered 3/1, 2012 at 14:19 Comment(0)
R
2

With Objective-C++ there is no reason you can't just define stichgroundvectswith: as -(void)stitchgroundvectswith:(std::vector<bVect2>&)vets num:(int)num just like if you were working in straight C++. C++ objects can be seamlessly (with certain caveats) integrated into Obj-C methods in this mode.

Rhombencephalon answered 3/1, 2012 at 14:16 Comment(0)
P
2

As @H2CO3 and @Joshua Weinberg point out, Objective-C++ lets you define a method with an argument of type std::vector (or a reference thereof, etc.). This will work fine if you're staying within Objective-C++ for all files that include the relevant .h. If, however, you need to import that header into Objective-C-compiled files, you'll need to pass the pointer, and hide the type from Objective-C code:

#ifdef CPLUSPLUS
typedef std::vector* vecp_t
#else
typedef void* vecp_t
#endif

@interface MyClass
{}

- (void)anOtherMethodCalledFromObjC;
- (void)stitchGroundVectsWithVector:(vecp_t)vec;
@end

(I've taken the liberty of Objective-C stylizing your method names)

Parental answered 3/1, 2012 at 14:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.