object_getIvar fails to read the value of BOOL iVar
Asked Answered
C

4

0

object_getIvar(id object, Ivar ivar) reads the values of iVArs properly but fails on a BOOL type iVar and crashes. I need the values of all iVars of a class.Is there any way to resolve it.

Ceramist answered 2/12, 2011 at 12:19 Comment(1)
Can you post the code you're using to read the ivars? We also would be more equipped to help if you provided the specific error message that accompanies the crash.Ramey
T
4

object_getIvar seems to return the actual value (not an id) which is in opposition to what the manual says. If you are using ARC, this will cause an immediate processor fault during attempt to retain the returned value which is not an object.

object_getInstanceVariable() returns a pointer to the information, but ARC refuses to accept the function.

Torment answered 31/3, 2012 at 23:47 Comment(0)
T
23

Accessing ivars directly can be done using ARC. You can access both basic C types (char, short, int, etc.) and Objective-C objects. For example, an unsigned char ivar can be accessed using the following pattern. Replacing the type name with other basic types yields an accessor for that type of ivar.

unsigned char val;

val = ((unsigned char (*)(id, Ivar))object_getIvar)(object, ivar);

NSLog(@"Looks like I got: %u (or character %c)", val, val);

Behind the scenes, you're employing some shenanigans to fake the compiler into thinking that object_getIvar() is actually a function returning the type you are after. This kind of type cast changes the way the compiler calls and interprets the result of object_getIvar, and is required because the basic C types can be 8 to 64 bits big, and only the compiler knows how they're handled when used as return values, which is defined by the ABI used by the architecture you are compiling for.

Yes it looks funny, but it's the most portable way to do it, and, well, it just works. :-) Using a straight type cast will not work, nor will ARC allow you to do it.

If the ivar is an object derived from NSObject, you can use the return value directly, or type cast it to the object you're expecting without issues, ARC or no ARC.

Trimer answered 12/12, 2012 at 3:48 Comment(2)
This should be the accepted answer. Not only is it the only one that actually answers the question in a way that works, it is a great answer! Actionable, gives background info, links, and is short and to the point. Thanks, Jim!Bulky
The same also seems to work with object_setIvar, for example: ((void (*)(id, Ivar, unsigned char))object_setIvar) (object, ivar, val)Semolina
D
5

The answers are a bit old. With ARC and structs (or to be safe when accessing any non-object iVar), you should do it like this instead:

ptrdiff_t offset = ivar_getOffset(ivar);
unsigned char *stuffBytes = (unsigned char *)(__bridge void *)object;
CGRect gilligans = * ((CGRect *)(stuffBytes + offset));

At least this was the only way to get it working for me.

Taken from this page: http://www.bignerdranch.com/blog/inside-the-bracket-part-5-runtime-api/

Dropsical answered 8/6, 2014 at 15:12 Comment(0)
T
4

object_getIvar seems to return the actual value (not an id) which is in opposition to what the manual says. If you are using ARC, this will cause an immediate processor fault during attempt to retain the returned value which is not an object.

object_getInstanceVariable() returns a pointer to the information, but ARC refuses to accept the function.

Torment answered 31/3, 2012 at 23:47 Comment(0)
S
1

I know it's a bit too late to comment :) But I faced the same issue and all the approaches had different problems. ivar_getOffset doesn't pass the address sanitizer at least. But everything works with KVC. So, instead of using the pointers, just use [object setValue: value forKey: key], where value is your wrapped value (use @(value) for plain/fundamental values) and key is the name of your ivar.

Steadman answered 4/9, 2018 at 16:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.