Question

Objective-C's @encode produces C strings to represent any type, including primitives, and classes, like so:

NSLog(@"%s", @encode(int));       // i
NSLog(@"%s", @encode(float));     // f
NSLog(@"%s", @encode(CGRect));    // {CGRect={CGPoint=ff}{CGSize=ff}}
NSLog(@"%s", @encode(NSString));  // {NSString=#}
NSLog(@"%s", @encode(UIView));    // {UIView=#@@@@fi@@I{?=b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b6b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b3b1b1b1b2b2b1}}

So, I can get a meaningful encoding of a class (one that contains the class name) using @encode(ClassName), but it's also in the same format as the encoding of a generic struct (as in the above example).

Now, my question is, given any (valid of course) type encoding, is it possible to find out whether the encoding is of an Objective-C class, and if so, to get the Class object that corresponds to that encoding?

Of course, I probably could just try to parse the class name out of the type encoding, and get the class from that using NSClassFromString, but that just doesn't sound like the right way to do it, or particularly performance-efficient. Is this really the best way to achieve this?

Was it helpful?

Solution

Unfortunately, I do not think there is a way to be sure that you are working with a class using the encoding.

dasblinkenlight has a good idea in the comments, although he didn't support other instance variables. The full format for a class is {CLASSNAME=#IVARS}. However, this could potentially catch other structures as well, as I will explain below.

The reason classes are encoded like this are that they are treated just like structures by @encode. The { indicates the start of a structure, and is followed by the structure's name and an equals sign, then the contents, and finally }. The reason all classes have # after the equals sign is that the first element in a class structure is of type Class, and that is how this type is encoded. What this means is that any structure beginning with a Class will match this format. If there are any instance variables listed, they will be encoded after the #. For example, here is a reconstruction of UIView using the encoding you posted.

Structure                         Encoding

struct UIView {                   {UIView=
    Class class1;                  #
    id id1, id2, id3, id4;         @@@@  Object pointers always encode as id.
    float float1;                  f
    int int1;                      i
    id id5, id6;                   @@
    unsigned int uint1;            I
    struct /*anonymous*/ {         {?=
        unsigned bitfield1 : 1;     b1   The type of bitfield is not encoded.
        unsigned bitfield2 : 1;     b1   I just chose unsigned.
        ...
        unsigned bitfield15 : 1;    b1
        unsigned bitfield16 : 6;    b6
        unsigned bitfield17 : 1;    b1
        ...
        unsigned bitfield58 : 1;    b1
        unsigned bitfield59 : 3;    b3
        unsigned bitfield60 : 1;    b1
        unsigned bitfield61 : 1;    b1
        unsigned bitfield62 : 1;    b1
        unsigned bitfield63 : 2;    b2
        unsigned bitfield64 : 2;    b2
        unsigned bitfield65 : 1;    b1
    };                             }
}                                 }

(decoded using the _C_* constants in /usr/include/objc/runtime.h)

If you were to put this structure in your code (filling in the ...s), both @encode(UIView) and @encode(struct UIView) will give you the same result. Interestingly, beginning a structure with a class technically would make it a valid class type, and you could successfully send messages to a pointer to one. Beware, however, that only instance variables defined in the class interface are placed in the encoding, as the locations of others are determined at runtime, so taking advantage of this to create your own objects is not advised.

OTHER TIPS

There is no built-in way to do that, but several people saw the potential in reverse-engineering of parsing @encode output. I don't own this project, but nygard's class-dump might provide you with everything you need to make sense out of a @encode string.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top