Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decode Class from @encoded type string

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?

like image 340
Greg Avatar asked Aug 10 '13 11:08

Greg


People also ask

How do you decode an encoded string?

So first, write the very first character of the encoded string and remove it from the encoded string then start adding the first character of the encoded string first to the left and then to the right of the decoded string and do this task repeatedly till the encoded string becomes empty.

What does decode () do in Python?

Python bytes decode() function is used to convert bytes to string object. Both these functions allow us to specify the error handling scheme to use for encoding/decoding errors. The default is 'strict' meaning that encoding errors raise a UnicodeEncodeError.

How do I decode a UTF-8 string in Python?

To decode a string encoded in UTF-8 format, we can use the decode() method specified on strings. This method accepts two arguments, encoding and error . encoding accepts the encoding of the string to be decoded, and error decides how to handle errors that arise during decoding.

How do you decode an encoded string in Python?

decode() is a method specified in Strings in Python 2. This method is used to convert from one encoding scheme, in which argument string is encoded to the desired encoding scheme. This works opposite to the encode. It accepts the encoding of the encoding string to decode it and returns the original string.


1 Answers

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.

like image 65
ughoavgfhw Avatar answered Sep 20 '22 20:09

ughoavgfhw