'Assigning to 'id' from incompatible type' - objective-c

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;

Related

Objective c — Update parameter in block

I was doing some tinkering with tree traversals (which I have solved in a much more straightforward way) but I have come across an issue in the following piece of Objective C logic:
- (NSString *)someWrapperFunction
{
NSString *result = #"";
NSString *(^appendBlock)(int, NSString **) = ^NSString *(int a, NSString **adder){
if (a == 0)
{
// base case
return #"";
}
NSLog(#"%d", a);
*adder = [*adder stringByAppendingFormat:#"-%d-", a];
NSLog(#"adder: %#", *adder);
return [*adder stringByAppendingString:appendBlock(a-1, adder)];
};
appendBlock(5, &result);
return result;
}
Basically, I want to create a block of code that concatenates numbers into the given string (adder). The result should be: "-5--4--3--2--1-".
I get a segmentation fault with the above code but with some other code that I wrote for the tree traversal, the adder string was essentially not getting updated. Any pointers to what I am doing wrong here? (Is it possible that the variable that is being updated by the inner block (inside recursion) is disallowed as it is already being occupied by the outer block OR is it just that NSString is non-mutable data type?)
In any case, I want to keep the design of the function the same; how would I solve this problem (using c/objective)?
After some searching and experimenting I found a way to fix this.
There is no reason to be using a double-pointer for your adder parameter in the block. Just use a regular pointer and update your code accordingly.
The error is coming from the fact that inside of the block, appendBlock is NULL and you end up dereferencing the NULL pointer trying to call it.
Here's an updated version that works:
- (NSString *)someWrapperFunction
{
NSString *result = #"";
NSString *(^appendBlock)(int, NSString *);
__block __weak NSString *(^weakBlock)(int, NSString *);
weakBlock = appendBlock = ^NSString *(int a, NSString *adder){
NSString *(^innerBlock)(int, NSString *) = weakBlock;
if (a == 0)
{
// base case
return #"";
}
NSLog(#"%d", a);
adder = [adder stringByAppendingFormat:#"-%d-", a];
NSLog(#"adder: %#", adder);
// Split this update to make it easier to debug.
NSString *update = innerBlock(a-1, adder);
return [adder stringByAppendingString:update];
};
appendBlock(5, result);
return result;
}
Output: "-5--4--3--2--1-"
This update is rewritten for point #1 (which really has nothing to do with your original issue.
To solve point #2 this update creates the original appendBlock variable as well as a new __block __weak weakBlock reference to the same block. And then inside the block, a new (strong) block pointer is created to reference the weak block pointer. Without the use of the weak pointer, the code works but causes a warning.

__unsafe_unretained in struct

Let say I have a struct in which I declare like so:
struct myStruct
{
NSString *aString;
}
The above gives error.
I can, however, fix the error by:
struct myStruct
{
__unsafe_unretained NSString *aString;
}
It silences the error, but will crash at runtime, because I suppose aString is immediately released.
I have tried __strong instead but it won't compile.
Is there any other way I can store an object within the struct and use it properly?
You can create a new object and use this as a pointer to a struct (as this is what a Objective C object is). So if you create a subclass of NSObject with instance variables that you require you can treat it exactly like a pointer to a structure (once you have initialised it). i.e.
myObj = [[myObjClass alloc] init];
myObj->instanceVariable1 = #"myString";
As mentioned in the comments below you need to declare the variables in the interface like this:
#interface myObjStruct : NSObject
{
#public
NSString *instanceVariable1;
}
With an NSString you can use a CFStringRef instead, or cast your NSString * to a CFString and retain it with a CFRetain(), or use CFBridgingRetain to get the incremented retain count immediately. You can do this with any type that is toll free bridged from a CF type (such as CFArray CFDictionary).
struct testStruct {
CFStringRef str;
};
- (void)aMethod
{
NSString *string = #"Hello struct";
struct testStruct test = {
CFBridgingRetain(string),
};
}
You now have ownership of the string, and will need to call CFRelease on the test.str at some point to not leak memory. To get a NSString back you cast it like this NSString *string = (__bridge NSString *)test.str;.
The above code has incremented the retain count of the string object. It's possible to get this to work for any object like this:
struct testStruct {
__unsafe_unretained AnyObj *obj;
};
- (void)aMethod
AnyObj *aObj = [[AnyObj alloc] init];
CFBridgingRetain(aObj); \\increment the retain count.
struct testStruct test = {
aObj,
};
aObj = nil;
NSLog(#"%#", aObj);
}
To release this object later you would need to do CFRelease((__bridge CFTypeRef)(test.obj));. Note that if you remove the CFBridgingRetain(aObj); this code will probably crash.
You could also try having a play with id objc_retain(id value); Although to use this you will need to manually include the arc.h header see How to import objc_retainAutoreleasedReturnValue? you would use this to increment the retain value much like the code above but without the need for casting. You'd also have to use the equivalent release function.
Toll-Free Bridged Types
__bridge transfers a pointer between Objective-C and Core Foundation with no transfer of ownership.
__bridge_retained or CFBridgingRetain casts an Objective-C pointer to a Core Foundation pointer and also transfers ownership to you. You are
responsible for calling CFRelease or a related function to relinquish
ownership of the object.
__bridge_transfer or CFBridgingRelease moves a non-Objective-C pointer to Objective-C and also transfers ownership to ARC. ARC is responsible
for relinquishing ownership of the object.
Example (not recommend)
It seems __bridge_retained, __bridge_transfer don't allow ownership transfer to/from same type. So I used additional __bridge for type casting.
I've test confirmed NSString objects are released without leaks.
#define TEST_COUNT 10000
struct myStruct
{
NSString* __unsafe_unretained aString;
};
static struct myStruct* myArray = NULL;
static void allocString()
{
myArray = (struct myStruct*) malloc(sizeof(struct myStruct) * TEST_COUNT);
for (int i=0; i<TEST_COUNT; ++i)
{
NSString* v = [[NSString alloc] initWithFormat:#"%d", i];
myArray[i].aString = (__bridge NSString*)(__bridge_retained void*) v;
}
}
static void freeString()
{
if (myArray)
{
for (int i=0; i<TEST_COUNT; ++i)
{
if (myArray[i].aString)
{
NSString* v = (__bridge_transfer NSString*) (__bridge void*) myArray[i].aString;
v = nil;
}
}
free(myArray);
}
}

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);
}

Store an array of NSObject Pointers in C array

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?

C array of Objective C objects

I'm trying to create a C array of objective C NSStrings using malloc. I'm not doing it right, but I don't think I'm far off. Maybe someone can point me in the right direction.
Let's say we want 5 strings in our array for the sake of argument.
Interface:
#interface someObject : NSObject {
NSString **ourArray;
}
#property () NSString **ourArray;
#end
Implementation:
#implementation someObject
#synthesize ourArray;
-(id)init {
if((self = [super init])) {
self->ourArray = malloc(5 * sizeof(NSString *));
}
return self;
}
-(NSString *)getStringAtPos3 {
if(self.ourArray[3] == nil) {
self.ourArray[3] = #"a string";
}
return self.ourArray[3];
}
#end
When I set a breakpoint in getStringAtPos3 it doesn't see the array element as nil so it never goes into the if statement.
mallocing an array of pointers is done as follows:
self->ourArray = malloc(5 * sizeof(NSString *));
if (self->ourArray == NULL)
/* handle error */
for (int i=0; i<5; i++)
self->ourArray[i] = nil;
malloc doesn't make guarantees about the contents of the returned buffer, so set everything to nil explicitly. calloc won't help you here, as a zero pattern and nil/NULL aren't the same thing.
Edit: even though zero and null may be the same on i386 and arm, they are not the same conceptually, just like NULL and nil are strictly not the same. Preferably, define something like
void *allocStringPtrs(size_t n)
{
void *p = malloc(sizeof(NSString *));
if (p == NULL)
// throw an exception
for (size_t i=0; i<n; i++)
p[i] = nil;
return p;
}
One issue is this:
self->ourArray = malloc(5 * sizeof(NSString *)); // notice the sizeof()
I figured out the problem - I should have been using calloc, not malloc. While malloc simply allocates the memory, calloc
contiguously allocates enough space for count objects that are size bytes of memory each and returns a pointer to the allocated memory. The allocated memory is filled with bytes of value zero.
This means you get an array of nil objects essentially as in objective c 0x0 is the nil object.