ValueForKey: on a packed structure?

Given the following packed structure:

typedef struct __attribute__((packed)) { BOOL flag; int x; } Foo; 

And the following class:

 @interface Obj : NSObject @property (nonatomic) Foo foo; @end @implementation Obj @end 

Trying to call valueForKey: for a property that has a packed structure type:

 Obj *obj = [Obj new]; id boo = [obj valueForKey:@"foo"]; 

causes a crash inside valueForKey: (in fact, it does not valueForKey: inside valueForKey: but in random places depending on the size of the moon, I think this is memory corruption).

If I remove __attribute__((packed)) , it works fine. Any opportunity to get structure data without crashing? Is this an Apple bug?

PS. I need to do this at runtime, i.e. I can't just call .foo directly, I only have the @"foo" line at runtime. (What I'm trying to achieve is recursively print the contents of an object).

+4
source share
2 answers

Avoid KVO for your use case and stick with the dandy <objc/runtime.h> convenient header. You can reimplement the bulk of KVO using this introspection. Structural packaging is used primarily to ensure that the compiler does not align internal fields properly, so the CPU should not process it at the hardware level at run time. On this day and aged, it is best for the compiler to take care of things for you.

If you really prefer this packaging structure (as you said in a network transfer scenario), I will need more information to determine where the problem is. Perhaps try changing @property (nonatomic) Foo foo; on @property (nonatomic) NSValue *foo; and then insert it and unzip it yourself? So the exception / error will be in your application domain.

0
source

I don’t know if this is possible with properties, but if it is, I don’t think you are using the correct syntax.

You tried to change

 id boo = [obj valueForKey:@"foo"]; 

to read

 Foo boo = obj.foo; 

?

Foo is not and never will be id . valueForKey: returns id, and the runtime may be blocked by trying to compress struct Foo in NSValue .

If for some reason you need to use valueForKey: your calls should look like.

 Foo myFoo = FooFactory(); Object *myObj = [Object new]; [myObj setValue:@( myFoo ) forKey:@"foo"]; Foo myFooOut; [[myObj valueForKey:@"foo"] getValue:&myFooOut]; //I bet `getValue:` is where things are barfing. 

In this case, if the NSValue mechanism really cannot handle the packed structure, you just need to write the accessors in the old-fashioned way: -<key> and -set: `.

PS: Never call the class "Object", in fact there is an Object in some SDKs that NSObject inherits. I guess only in your example.

0
source

All Articles