The classification of the underlying implementation principle on iOS

IOS classification is how to achieve the bottom?
this article will be divided into four modules to explore

  1. Classified structure
  2. Compile time classification
  3. Load classification
  4. summary

This article uses the runtime version of the source code is objc4 – 680
in the class and classification code is as follows

@interface Person: NSObject / / @property (nonatomic, copy) NSString *presonName; @end @implementation Person (void) doSomeThing{NSLog (@ Person);} @end
The classification of @interface Person (categoryPerson) / @property (nonatomic, copy) NSString *categoryPersonName; @end @implementation Person (categoryPerson) - (void) doSomeThing{NSLog (@ categoryPerson);} @end

1 classified structure

Struct _category_t {const char *name; / / _class_t / / struct class *cls class const struct _method_list_t; *instance_methods; //category all add to the list of instance methods (instanceMethods) const struct _method_list_t *class_methods //category in the list; all the added methods (classMethods) const struct _protocol_list_t *protocols; a list of all the //category protocol (the protocols const struct _prop_list_t *properties); all the attribute added in //category (instanceProperties)}; struct category_t {const char *name; / / CLS / / struct method_list_t classref_t class; class *instanceMethods classification is an instance method; / / list of struct method_list_t *classMethods; / / class method Table struct protocol_list_t *protocols struct property_list_t *instanceProperties; / / protocol list follow; / / / / if the attribute list is returned for class list; otherwise it returns a list of method_list_t *methodsForMeta instance method (bool isMeta) {if (isMeta) {return classMethods;} else {return instanceMethods;}} / / if class returns nil no, because the metaclass attributes; otherwise it returns an instance attribute list, but... (bool isMeta *propertiesForMeta property_list_t instance attribute) {if (isMeta) {return nil; / / classProperties;} else {return instanceProperties;}}};

2 compile time classification

2.1 classification attributes

/ / Person (categoryPerson) static struct /*_prop_list_t*/ attribute list {unsigned int entsize; / / sizeof (struct _prop_t) unsigned int count_of_properties; struct _prop_t prop_list[1];} _OBJC_$_PROP_LIST_Person_$_categoryPerson (__attribute__ (used, section (__DATA, __objc_const))) = {sizeof (_prop_t), turning 1, "categoryPersonName", "[email protected]/" NSString/ "C, N"}}}; / / Person static struct /*_prop_list_t*/ attribute list {unsigned int entsize; / / sizeof (struct _prop_t) unsigned int count_of_properties; struct _prop_t prop_list[1];} _OBJC_$_PROP_LIST_Person (__attribute__ (used, section (__DATA, __objc_const))) = {sizeof (_prop_t), 1, turning "presonName" [email protected]/ "," NSString/ ", C, N, V_presonName}}};

The above code can be found: in the classification can be declared attributes, and will also generate a _prop_list_t structure

2.2 classification of instance variables?

Static struct / / Person instance variable list /*_ivar_list_t*/ {unsigned int entsize; / / sizeof (struct _prop_t) unsigned int count; struct _ivar_t ivar_list[1];} _OBJC_$_INSTANCE_VARIABLES_Person (__attribute__ (used, section (__DATA, __objc_const))) = {sizeof (_ivar_t), 1 (unsigned long, turning int * OBJC_IVAR_$_Person$_presonName, &); "_presonName", "@/" NSString/ ", 3, 8}}};

Because of this structure _category_t and no _ivar_list_t
so at compile time system without Person (categoryPerson) did not generate the corresponding structure similar, no generation of _categoryPersonName.

2.3 examples of classification methods

/ / Person instance method structure static struct /*_method_list_t*/ {unsigned int entsize; / / sizeof (struct _objc_method) unsigned int method_count; struct _objc_method method_list[3];} _OBJC_$_INSTANCE_METHODS_Person (__attribute__ (used, section (__DATA, __objc_const))) = {sizeof (_objc_method), 3 (struct * objc_selector), turning the "doSomeThing". "[email protected]:8" (void *) _I_Person_doSomeThing} (struct * objc_selector) {"presonName", "@[email protected]:8" (void *) _I_Person_presonName} (struct * objc_selector) {"setPresonName:", "[email protected]:[email protected]" (void * _I_Person_setPresonName_}})}; / / Person (categoryPerson) static struct /*_method_list_t*/ instance method structure {unsigned int entsize; / / sizeof (struct _objc_method unsigned) Int method_count; struct _objc_method method_list[1];} _OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_categoryPerson (__attribute__ (used, section (__DATA, __objc_const))) = {sizeof (_objc_method), 1 (struct * objc_selector), turning the "doSomeThing", "[email protected]:8" (void * _I_Person_categoryPerson_doSomeThing}})};

In contrast to the above method we can see: Although classification can declare attributes, but when compiling system does not generate get / set method, so the classification attribute, which is why the classification using
runtime dynamically add attributes, how to dynamically add attributes, interested students can see the following article in iOS classification by runtime to add dynamic attributes

2.4 classified structure

/ / Person (categoryPerson) static struct _category_t _OBJC_$_CATEGORY_Person_$_categoryPerson __attribute__ structure ((used, section (__DATA, __objc_const))) = {"Person", 0 / / & (const struct; OBJC_CLASS_$_Person, _method_list_t * & _OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_categoryPerson, 0), 0 (const, struct * _prop_list_t & _OBJC_$_PROP_LIST_Person_$_categoryPerson});

This is the
_OBJC_$_CATEGORY_Person_$_categoryPerson generated by the system instantiated at compile time _category_t

2.5 sorting array

Static struct *L_OBJC_LABEL_CATEGORY_$[1] __attribute__ ((__DATA, section, __objc_catlist, regular, no_dead_strip)) = {& _OBJC_$_CATEGORY_Person_$_categoryPerson,}, used;

Finally, the compiler generates an array, the array of elements that are created by each of the categories used to load the classification at run time.

3 load classification

3.1 load classification call stack

_objc_init - map_2_images - map_images_nolock - _read_images

Class load call stack as above

  • _objc_init is the entrance of the entire objc4, a number of initialization operations, the registration of the image state change callback function
  • Map_2_images is mainly locked and called map_images_nolock
  • Map_images_nolock in this function, the completion of all the class registration, fixup, and so on, as well as the initialization of the automatic release pool, initialization side table and other functions in the back end of the function called _read_images
  • _read_images method to do a lot of hard work, such as loading classes, Protocol, Category, loading the classification code written in the tail of the _read_images function

The call stack entry function void _objc_init (void) in, interested students can look at these functions have done

3.2 _read_images in the classification of the source code

Load classification of the source code to do two things

  • Add category instance methods, protocols, and attributes to the class
  • Add the category class methods and protocols to the class metaclass

Omit the code that has nothing to do with this article

Get all category_t / / **catlist = _getObjc2CategoryList image classification in (HI, & count); / / catlist for traversal (I = 0; I < count; i++) {category_t *cat = catlist[i]; Class = CLS remapClass (cat-> CLS); if (cat-> instanceMethods cat-> protocols || ||; cat-> instanceProperties {addUnattachedCategoryForClass (CAT), CLS, HI); if (cls-> isRealized) {(remethodizeClass) (CLS); classExists = YES;}} if (cat-> classMethods || cat-> protocols / * cat-> * / ||; classProperties) {addUnattachedCategoryForClass (cat, cls-> ISA (HI), if (cls->); ISA; -> isRealized) (()) {remethodizeClass (cls-> ISA) () }}

Do these things are mainly used in the following two functions

  • AddUnattachedCategoryForClass (cat, CLS, HI)
    did not add the classification attachment execution process of pseudo code for the class:
    1 stores all unattached classification list NXMapTable (*cats = unattachedCategories); 2 cats from the list of the inverted CLS unattached classification list category_list (category_list * *list = NXMapGet (cats, CLS)); classification cat 3 will be new to add just open position on the list-> list[list-> count++] = (locstamped_category_t) {cat, catHeader}; 4 new list back into the cats, will cover the old list NXMapInsert (cats, CLS, list); after the execution of the process, the classification system will put unattached classification of a CLS corresponding to the list (a little tongue. The list…), remethodizeClass (CLS) method reach
  • RemethodizeClass (CLS)
    implementation process of pseudo code:
    1 CLS class unattached classification list category_list (CLS, *cats = unattachedCategoriesForClass false/*not realizing*/) 2 unattached classification list attach to the CLS class attachCategories (CLS, cats, true / empty cache flush caches*/ method); executing the above process, the system the example method, category protocol and add attributes to the class
  • Finally, look at the
    attachCategories (CLS, cats, true / empty cache flush caches*/ method) within the implementation process of
    1 on the heap creating method, attribute, protocol array method, used to store the classification attribute, protocol method_list_t * * mlists = (method_list_t) malloc (cats-> count * sizeof (*mlists)) property_list_t; **proplists = (property_list_t) malloc (cats-> count * sizeof (*proplists)); protocol_list_t **protolists = (protocol_list_t) malloc (cats-> count * sizeof (*protolists)); 2 cats traversal method, remove the classification, properties, protocols, and the array is filled into the code to create the int mcount = 0; / / the method of recording int number propcount = 0; / / attributes of the record number of int protocount = 0; / / record protocol number Int i = cats-> count; / / from the start, to ensure the first classification of the latest bool fromBundle = NO; / / records are from bundle in while (i–) {/ / from the back after the traversal of auto& entry = cats-> list[i]; / / locstamped_category_t / / remove the list type classification, classification method of; if it is made is the class list; otherwise the list is an instance method method_list_t *mlist => methodsForMeta (isMeta); if (MLIST) {mlists[mcount++] = MLIST; / / will list in the mlists list fromBundle |= array entry.hi-> (isBundle); / / classification of the head information stored in it is bundle, the removal of remember} / / classification attribute list, if nil property_list_t *proplis is made in class T => propertiesForMeta (isMeta); if (proplist) {proplists[propcount++] = proplist; / / the attribute list into proplists attribute list array classification follow out} / / protocol_list_t *protolist protocol list => PROTOCOLS; if (protolist) {protolists[protocount++] = protolist; / / protolists protocol in the protocol list list array} 3 remove the CLS} class_rw_t data auto RW = cls-> data (4); storage method, attribute, protocol RW / / array to prepare prepareMethodLists method in mlists (CLS, mlists, mcount/* list the number of NO/* is not a basic method of * * *, fromBundle/*, whether from bundle*/); / / will be added to the list of new properties the rw-&gt attribute list in the RW array; properties.attachLists (propl Ists, propcount); / / release of proplists free (proplists); / / proplists / / will release new protocol list is added to the rw-&gt RW protocol list array (protolists; protocols.attachLists, protocount); / / release of protolists free (protolists); / / protolists / / release will be added to the list of rw-&gt RW protocol in the protocol list in the array; protocols.attachLists (protolists, protocount); / / release of protolists free (protolists);

4 Summary

At this point, the paper draws to a close,
hopes that the readers of this article will be able to understand

  • Classified structure
  • Whether you can add attributes in the classification
  • Is there an instance variable in the classification
  • How attach is classified into classes

The line of simple, if you have any questions, please.