std::vector in objective c method

12,327

Solution 1

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.

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

Solution 3

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.

Share:
12,327
coasty
Author by

coasty

Updated on June 04, 2022

Comments

  • coasty
    coasty almost 2 years

    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?

  • coasty
    coasty over 12 years
    Thanks for your help and advice Rob!