The runtime is introduced

Objective-c is a very dynamic programming language, which is very different from C, C++ and other languages. The dynamic nature of Objective-C is supported by the Runtime API. The Runtime API provides interfaces in C, and the source code is written in C++ assembly language

Runtime data structure

objc_object

objc_class

  • Class_rw_t structure
    • Methods, properties, and protocols in class_rw_t are two-dimensional arrays that can be read and written and contain the initial content of classes and classified content
  • Class_ro_t structure

  • Method_t structure
    • Method_t is a wrapper around the method \ function

  • Cache_t structure
    • The Class internal structure has a method cache (cache_t), which uses hash tables (hash tables) to cache previously called methods to speed up method lookups

OC Object classification

Instance objects

An instance object is an object that comes out of the alloc class, and each call to alloc generates a new instance object. The instance object stores information in memory including

  • Isa pointer
  • Other member variables

Class object

When we talk about classes, they are actually objects, called class objects, and each class has only one class object in memory. Class objects store information in memory mainly including

  • Isa pointer
  • Superclass pointer
  • Class property information (@Property)
  • Class instance method information
  • Class protocol information (Protocol)
  • Class member variable information (IVAR)

Yuan class object

Each class has one and only one meta-class object in memory. Meta-class objects have the same memory structure as class objects, but their purpose is different. The information stored in the memory mainly includes

  • Isa pointer
  • Superclass pointer
  • Class method information of a class

Isa to

  • Instance isa points to class
    • When an object method is called, the class is found through instance’s ISA, and finally the implementation of the object method is found to call
  • Class’s ISA points to meta-class
    • When a class method is called, the meta-class is found through the class isa, and the implementation of the class method is finally found to call
  • The ISA of the meta-class points to the meta-class of the base class

Message mechanism

The method call nature of OC sends a message to the method caller

The messaging

  • When the message receiver is empty, the objc_msgSend function is terminated

  • When the message receiver has a value, look at the cache

  • If the method has not been cached, the list of methods is queried

  • When no method is found in the cache to call, it is searched in the list of methods and stored in the cache cache if found

  • Methods exist in CLS -> RW ->methods, and methods is a two-digit array, so we need to iterate through the query. Here we get a one-dimensional array and call search_method_list

  • Looking for a method in a one-dimensional array, there are two cases

    • The first: list of methods have been sorted, through findMethodInSortedMethodList function finds, findMethodInSortedMethodList function is using a binary search query methods
    • The second way is that the list of methods is not sorted and will be searched one by one
  • When a method is found, it is first stored in the cache

  • If it doesn’t find a method to call in its own class object, it looks to see if that method exists in its parent class

    • 1. The search will go through all the parent classes layer by layer. As long as a parent class finds a method, the search will end
    • 2. Search the parent cache first. If the parent cache is found, the parent cache is saved first
    • 3. If the method does not exist in the cache of the parent class, the system searches for it in the list of methods of the parent class. If the method is found, the system stores it in its cache, but not in the cache of the parent class
    • 4. If no method is found, the for loop checks whether there is a method in the parent class, and so on. If the method is found, the query ends and the method is saved in the cache
  • If you don’t find it, you move on to the next stage, dynamic parsing

Dynamic method parsing

  • When a message is sent and the method to call is not found, it enters the dynamic method resolution phase.

  • In the process of dynamic method resolution, class objects and metaclass objects are judged and processed respectively

    • Class objects call the resolveInstanceMethod: method
    • The metaclass object calls the resolveClassMethod: method
  • We can use Runtime to add implementations of other methods in the + (BOOL)resolveInstanceMethod:(SEL) SEL method

forward

  • When dynamic method parsing does not find the method implementation to call, the message forwarding phase occurs. Call the forwardingTargetForSelector: method

    • Can in the method + forwardingTargetForSelector: set forward object
    • The principle of objc_msgSend is to send a message to the message receiver, and the message is of type SEL, regardless of whether it is a class method (+) or object method (-).
    • So, we can set the message receiver as the instance object
  • Method to realize + forwardingTargetForSelector: if not, it will call + methodSignatureForSelector: method, and call + forwardInvocation: method

super

Super principle

  • The bottom layer of super calls the objc_msgSendSuper method and passes in two arguments

    • __rw_objc_super: structure
      • Receiver: indicates the message receiver
      • Super_class: Finds the method to call starting with super_class
    • SEL sel_registerName (” run “) : method
    struct objc_super {
       __unsafe_unretained _Nonnull id receiver;
       __unsafe_unretained _Nonnull Classsuper_class; }; Copy the codeCopy the code
  • As you can see from the actual code, these two member variables are passed self and [Person Class], respectively.

  • So the message receiver is self and starts looking for methods in [Person Class]

Super meaning

  • Super means that the starting point of the query method is the parent class, not its own class object
  • The message receiver is self, not a superclass object
  • The sent message is the invoked method

Dynamic method parsing

  • @dynamic
    • Dynamic runtime languages defer function decisions to runtime.
    • Compile time Languages make function decisions at compile time.

Methods exchange

The Runtime application

  • Method Swizzle
  • Add attributes to categories
  • Realize automatic archiving and automatic unarchiving of classes
  • Implement dictionary to model

Runtime API

class

Create a class dynamically (parameter: Parent class, class name, Extra memory space) Class objc_allocateClassPair(Class superclass, const char *name, Void objc_registerClassPair(Class CLS) Destroy a Class void objc_disposeClassPair(Class) Class object_getClass(id obj); CLS; Class CLS) Determines whether an OC object is aClass BOOL object_isClass(ID obj) Determines whether aClass is a metaclass. BOOL class_isMetaClass(Class CLS) Retrieves the parent Class class_getSuperclass(Class cls)Copy the code

Member variables

Ivar class_getInstanceVariable(Class CLS, Const char *name) Ivar *class_copyIvarList(Class CLS, Void object_setIvar(id obj, Ivar Ivar, id value) id object_getIvar(id obj, BOOL class_addIvar(Class CLS, const char * name, size_t size, BOOL class_addIvar(Class CLS, const char * name, size_t size, uint8_t alignment, Const char * types) gets information about member variables const char *ivar_getName(Ivar v) const char *ivar_getTypeEncoding(Ivar v) Copies the codeCopy the code

attribute

Get a property objc_property_t class_getProperty(Class CLS, Const char *name) copy property list (free) objc_property_t *class_copyPropertyList(Class CLS, Unsigned int *outCount) BOOL class_addProperty(Class CLS, const char *name, Const objc_property_attribute_t *attributes, unsigned int attributeCount) void class_replaceProperty(Class CLS, const char *name, const objc_property_attribute_t *attributes, Unsigned int attributeCount) gets some information about an attribute const char *property_getName(objC_property_t property) const char *property_getAttributes(objc_property_t property) Copies the codeCopy the code

methods

Method class_getInstanceMethod(CLS, SEL name) Method class_getInstanceMethod(CLS, SEL name) IMP class_getMethodImplementation(Class CLS, SEL name) IMP class_getMethodImplementation(Method m, IMP imp) void method_exchangeImplementations(Method m1, Method *class_copyMethodList(Class CLS, Unsigned int *outCount) BOOL class_addMethod(Class CLS, SEL name, IMP IMP, Const char *types) IMP class_replaceMethod(Class CLS, SEL name, IMP IMP, SEL method_getName(Method m) IMP method_getImplementation(Method m) SEL method_getName(Method m) IMP method_getImplementation(Method m) const char *method_getTypeEncoding(Method m) unsigned int method_getNumberOfArguments(Method m) char *method_copyReturnType(Method m) char *method_copyArgumentType(Method m, Unsigned int index) selector associated const char *sel_getName(SEL SEL) SEL sel_registerName(const char * STR) implement IMP with block as method imp_implementationWithBlock(id block) id imp_getBlock(IMP anImp) BOOL imp_removeBlock(IMP anImp)Copy the code
Method class_getInstanceMethod(CLS, SEL name) Method class_getInstanceMethod(CLS, SEL name) IMP class_getMethodImplementation(Class CLS, SEL name) IMP class_getMethodImplementation(Method m, IMP imp) void method_exchangeImplementations(Method m1, Method *class_copyMethodList(Class CLS, Unsigned int *outCount) BOOL class_addMethod(Class CLS, SEL name, IMP IMP, Const char *types) IMP class_replaceMethod(Class CLS, SEL name, IMP IMP, SEL method_getName(Method m) IMP method_getImplementation(Method m) SEL method_getName(Method m) IMP method_getImplementation(Method m) const char *method_getTypeEncoding(Method m) unsigned int method_getNumberOfArguments(Method m) char *method_copyReturnType(Method m) char *method_copyArgumentType(Method m, Unsigned int index) selector associated const char *sel_getName(SEL SEL) SEL sel_registerName(const char * STR) implement IMP with block as method imp_implementationWithBlock(id block) id imp_getBlock(IMP anImp) BOOL imp_removeBlock(IMP anImp)Copy the code