1

I'm doing my first steps in objective-c (after a long, long time away from it) by translating some Java code I wrote for an Android game. It seems like there is no container that can take an object, without casting it to id first? Or is there?

Specifically this is the code I'm trying to work with:

NSMutableArray *touchedBodies = [[NSMutableArray alloc] init];
// some additional code
if(![touchedBodies containsObject:(id)body]) {
    [touchedBodies addObject:(id)body];
}

The containsObject line passes fine, but on the touchedBodies addObject:(id)b I'm getting a "bad access" error. The body I'm trying to add is a legitimate Box2D b2Body.

When I tried to add the body directly, without casting it:

[touchedBodies addObject:body];

the compiler complains "Cannot initialize a parameter of type id with an lvalue of type b2Body* '

What am I missing?

Eddy
  • 3,533
  • 13
  • 59
  • 89

1 Answers1

5

First of all you never need to cast to an id type just because you can consider id as the Object class in Java: it's an implicit upcast that doesn't need to be explicit.

In second instance the problem occurs because 2dBody is a C++ class, not an Objective-C class. While you can mix Objective-C++ and C++ code (the former is a superset of the latter), you can't mix objects from these two languages without some workarounds.

You have mainly three solutions:

  • if 2dBody is a pointer, wrap it inside an NSValue: [touchedBodies addObject:[NSValue valueWithPointer:body]], this introduces some overhead with object allocations and you will need to cast it when you use it, 2dBody *b = (2dBody*)[value pointerValue]
  • if 2dBody is not a pointer then you could use an NSData: [NSData dataWithBytes:.. length:..], this introduces overhead, problems with memory management (unless you use noCopy variants), it introduces problems if the layout of the class is not standard, and you will need to cast it in any case
  • forget cocoa collections and use STL collections, they're more performant and they will manage everything seamlessly: vector<2dBody> touchedBodies; touchedBodies.push_back(body);.

I strongly suggest using STL collections, I personally use this approach

Jack
  • 131,802
  • 30
  • 241
  • 343
  • note: `NSData` copy would work only if the object is a standard layout type. and yes - `std::vector<2dBody>` is definitely the type to use in this case +1. – justin May 22 '13 at 14:24
  • Thanks very much, @Jack. But when I try it, std::vector touchedBods; I get a compiler error "b2Body does not refer to a value." What does it mean? – Eddy May 22 '13 at 14:39
  • And another error is "No member named 'vector' in namespace 'std'" – Eddy May 22 '13 at 14:54
  • I tried changing the compiler as shown here http://stackoverflow.com/questions/12819886/no-type-named-shared-ptr-in-namespace-std but no luck. – Eddy May 22 '13 at 15:15
  • That link you posted should definitely solve the problem, which version of Xcode do you have? do you `#include `? if C++11 is enabled I'm not sure you need `using namespace std;` and you can refer to it directly with `vector` instead that `std::vector`. – Jack May 22 '13 at 15:21
  • OK including the vector solves this issue. I'm accepting the answer (thanks!!) but if you can also help with this: now I need to get an objectAtIndex from my vector, and I don't seem to find the right method for it. I'm seeing front() to get the first object, but when I call b2Body bzero = touchedBodies.front() I get a 'variable of type b2Body has private deconstructor' compiler error. I understand what it means, but is there a solution? – Eddy May 22 '13 at 16:12
  • Here there is everything you need: http://www.cplusplus.com/reference/, in any case you can access elements with `.at(index)` or directly with `[]` operator which is overloaded, eg `myVector[10]`. – Jack May 22 '13 at 16:22
  • OK, yeah, I figured that out, but now when I compile the project I get a bunch of new errors. 'Type float cannot be narrowed to GLubyte..." in ccTypes.h, which is not part of my project but part of the library. I'm assuming changing the compiler preference to C++11 brings those -- and I don't have the tools to start debugging an entire library. So I guess this solution won't work :( Or am I despairing prematurely? – Eddy May 22 '13 at 16:36
  • I posted a new question with this issue. http://stackoverflow.com/questions/16698090/c11-for-xcode-errors – Eddy May 22 '13 at 17:29