@Encoded string decoding class

Objective-C @encode creates C lines to represent any type, including primitives and classes, for example:

 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 class encoding (the one that contains the class name) using @encode(ClassName) , but it is also in the same format as the general struct encoding (as in the above example).

Now, my question is that, given any (valid, of course) type encoding, you can find out if the encoding is an Objective-C class, and if so, get a Class object corresponding to that encoding?

Of course, I might just try to parse the class name from the type encoding and get the class from it using NSClassFromString , but it just doesn't seem like the right way to do this, or in particular, performance is efficient. Is this really the best way to achieve this?

+6
source share
2 answers

Unfortunately, I don’t think there is a way to make sure that you are working with a class using encoding.

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

Reason classes are encoded so that they are treated as structures using @encode . { indicates the beginning of the structure, followed by the name of the structure and the equal sign, then the contents, and finally } . The reason all classes have # after the equal sign is because the first element in the structure of the class is of type Class , and that is how this type is encoded. This means that any structure starting with Class will conform to this format . If there are listed instance variables, they will be encoded after # . For example, here is a reconstruction of a 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 _C_* constants in /usr/include/objc/runtime.h)

If you were to put this structure in your code (filling ... s), both @encode(UIView) and @encode(struct UIView) would give you the same result. Interestingly, starting a structure with a class would technically make it a valid type of class, and you could successfully send messages to one pointer. However, note that only instance variables defined in the class interface are placed in the encoding, since the locations of others are determined at run time, so using this to create your own objects is not recommended.

+6
source

There is no built-in way to do this, but several people saw the potential in reverse-engineering @encode . I do not own this project, but nygard class-dump can provide you with everything you need to understand the meaning of the @encode string.

+1
source

Source: https://habr.com/ru/post/951456/


All Articles