views:

386

answers:

4

if the variable in object_getIvar is a basic data type (eg. float, int, bool) how do I get the value as the function returns a pointer (id) according to the documentation. I've tried casting to an int, int* but when I try to get that to NSLog, I get error about an incompatible pointer type.

A: 

It's probably boxing the value in an NSNumber. You can verify this by NSLogging the returned id's className, like so:

id returnedValue = object_getIvar(self, myIntVar);
NSLog(@"Class: %@", [returnedValue className]);

Edit: I found another question just like this one here: http://stackoverflow.com/questions/1216262

From my own experimentation, it would appear that my original assumption was incorrect. int and float and other primitives appear to be returned as the actual value. However, it would be appropriate to use ivar_getTypeEncoding to verify that the returned value is the type that you're expecting it to be.

Dave DeLong
when I try to call [returnedValue className], I get warning no method className found. I then tried using object_getClassName(object_getIvar(self, myIntVar)) (myIntVar is actually allocated in a for loop so it changes) and the loop executes once and then I end up in GDB but there is no error logged. The only value that gets logged is 'nil'... ideas?
Russel West
@Russel I'm looking into it and experimenting. I'll edit my answer if I figure anything out.
Dave DeLong
Jacob got it to work using object_getInstanceVariable but I'm still curious about how to get object_getIvar to work because it is apparently faster ( http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html#//apple_ref/c/func/object_getIvar ) Tried searching the net for examples using it but nobody seems to use it with basic types.
Russel West
A: 

you can use object_getInstanceVariable directly: (haven't tested it)

void *ptr_to_result;
object_getInstanceVariable(obj, "intvarname", &ptr_to_result);
float result = *(float *)ptr_to_result;
newacct
I get incompatible pointer time on the 3rd argument.... I'm not terribly familiar with Obj-C I'm afraid. the docs say it should be a void pointer, thats the same as id i think? in which case i'm back to the same problem as above....
Russel West
okay i changed it to use void *. try it now
newacct
it now exits to GDB at the last line with no message as to why, compiles with no warnings however. If i hit continue at that line i get 'EXC_BAD_ACCESS' which I think is related to memory management. Any further thoughts? BTW I do check that my var typeEncoding = "f" before doing this so it cant be due to mismatch of variables/memory allocation etc. at least I dont think so.
Russel West
A: 

The value that is returned is the value from the right place in the object; just not the right type. For int and BOOL (but not float), you could just cast the pointer to an int or BOOL, since pointers and ints are the same size and they can be cast to each other:

(int)object_getIvar(obj, myIntVar)
newacct
this appears to work however.... i can use a case on the typeEncoding to handle the bools and the ints but for the floats I'm still searching for a solution.
Russel West
+1  A: 

Getting:

myFloat = 2.34f;

float myFloatValue;
object_getInstanceVariable(self, "myFloat", (void*)&myFloatValue);

NSLog(@"%f", myFloatValue);

Outputs:

2.340000

Setting:

float newValue = 2.34f;
unsigned int addr = (unsigned int)&newValue;

object_setInstanceVariable(self, "myFloat", *(float**)addr);

NSLog(@"%f", myFloat);

Outputs:

2.340000

Jacob H. Hansen
Russel West
Damn, you're right :)
Jacob H. Hansen
Any ideas for object_setInstanceVariable for a float? I can get it to work for an int viaint myInt = 5;int theInt;object_setInstanceVairable(self, "theInt", (void*)myInt);because pointers and ints are the same size, so it doesnt work for floats.
Russel West
I just edited in some working code for setting floats :)
Jacob H. Hansen
it does indeed work :) thanks! Could please explain why you need *(float**)? I understand that (float**) is casting addr as a pointer to a pointer to which you then dereference. But since addr holds the address of newValue, isnt addr just like a pointer, hence you only need to cast it as float* and dereference that? That doesnt work but I dont understand why. What am I missing?
Russel West