Introduction to the

  • Runtime: Runtime is a set of low-level C language APIS, which is the core of iOS. The developer can send a message to any object during coding, but at compile time it is determined that the message should be sent to the receiver, and how the receiver will respond to and process the message is up to the runtime.

  • Structural model

    1. Runtime memory model

      • isa

        • Structure of type ISA_t ()

        • Structurally, isa_t() is essentially a union type, which saves more space than a struct.

          • The definition of a union is that it allows several variables of different types to occupy a block of memory, which is determined by the type of member in the structure that takes up the largest byte
          • Variables in a union can overwrite each other, so that several different variables are stored in the same memory segment
        • In effect, it is similar to Pointers, with instance ISA pointing to aclass and class ISA pointing to a metaclass.

      • object

        • Yes objc_object isa C structure that contains only isa of type isa_t.
        • In practice, typedefs are used as id types
      • class

        • It inherits from Objc_Object, so a class is also a kind of object

        • Defines the names of methods that can accept messages

        • In addition to ISA, there are three member variables

          • A pointer to the superclass parent
          • Cache method cache
          • Bits Indicates the list of instance methods
      • metaclass

        • Stores all the class methods of a class
        • Every class will have metaclass.
      • Object – Class – Metaclass

        • Object’s ISA points to a class
        • The isa of the class points to metaclass
        • Metaclass isAs all point to the Root class, the Root class
        • The superclass of a class points to its parent class
        • The superclass of the metaclass refers to the metaclass of the superclass
        • The superclass of Root class points to NSObject
        • Object isa lookup, you can find the Root metaclass.
        • The superclass of the root metaclass points to NSObject
    2. Method invocation (message sending)

      • When an instance method of an object is called, it finds the corresponding class through ISA and then looks for the method in the class_datA_bits_t bits of that class.

        • Class_data_bits_t is the body of the mechanism that points to the data region of the class object
      • When an instance method of an objC_Object object is called, the implementation of the method is obtained in the class through the object’s ISA

      • When the class method of an objC_class object is called, the implementation of the method is retrieved in metaclass via the class isa

      • If the class does not have an implementation of a method, the search continues to the parent class

      • _objc_msgSend process

        1. Check whether the message receiver is nil or uses tagPointer

        2. According to the message recipient’s ISA

          1. The message recipient is the class, and ISA finds the metaclass
          2. The message receiver is the instance, and ISA finds the class
        3. Go into the CacheLookup process and look for the method cache

          1. If the cache has records, call directly

            1. Verify IMP validity by calling TailCallCechedImp
          2. If there are no cached records, go to the __objc_msgSend_uncached process

        4. __objc_msgSend_uncached call __class_lookupMethodAndLoadCache3 method, this method returns the IMP object, again call lookUpImpOrForward method

          1. Will be looked up again from the class’s method cache

          2. If successful, write to the cache and call, otherwise

          3. It looks in the parent’s cache, if it doesn’t find it it looks in the parent’s method list, so the loop knows the base class

          4. Base class haven’t found method, into the dynamic methods analytic process (resolveInstanceMethod | resolveClassMethod)

          5. Dynamic resolution fail, then into the forward process (forwardingTargetForSelector | forewordInvocation | methodSignatureForSelector)

          6. Message forwarding failed, IMP=nil, crash

1, Introduce the runtime memory model (ISA, object, class, metaclass, structure storage information, etc.)

Object:

Typepedef struct objc_object * ID; As can be seen from its structure, it includes an ISA pointer, which points to the Class object of this object. An object instance finds its own Class through this ISA, and this Class stores the method list, attribute list, member variable list and other related information of this instance.

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
Copy the code

Class:

A Class in OC is represented by a Class, which actually points to an objc_class pointer type, typedef struct objc_class *Class; The corresponding structure is as follows:

struct objc_class { Class _Nonnull isa OBJC_ISA_AVAILABILITY; #if ! __OBJC2__ Class _Nullable super_class OBJC2_UNAVAILABLE; const char * _Nonnull name OBJC2_UNAVAILABLE; long version OBJC2_UNAVAILABLE; long info OBJC2_UNAVAILABLE; long instance_size OBJC2_UNAVAILABLE; struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE; struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE; struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE; struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE; #endif }Copy the code

From the variables defined in the structure, the Class type of OC includes the following data (metadata) : super_class; Name (name of the class object); Version, INFO (version and related information); Instance_size (instance memory size); Ivars (list of instance variables); MethodLists; Cache; Protocols (list of implemented protocols);

Isa refers to a metaclass. The metaclass holds all the information about the method that created the Class object.

The following figure shows the relationship between OC objects, classes, and metaclasses

As you can see from the figure, the metaclass isa of the final base class (NSObject) points to itself, forming a closed loop.

A Meta Class is a Class of Class objects that contains information about Class methods.

Let’s look again at the structure that stores information about methods, attributes, member variables, and so on in the class object

** objc_iVAR_list: ** Stores member variables of the class, which can be obtained using object_getIvar or class_copyIvarList; The other two methods are class_getProperty and class_copyPropertyList, which are used to get the class’s property list. Properties and member variables are different.

struct objc_ivar {
    char * _Nullable ivar_name                               OBJC2_UNAVAILABLE;
    char * _Nullable ivar_type                               OBJC2_UNAVAILABLE;
    int ivar_offset                                          OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
}                                                            OBJC2_UNAVAILABLE;

struct objc_ivar_list {
    int ivar_count                                           OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
    /* variable length structure */
    struct objc_ivar ivar_list[1]                            OBJC2_UNAVAILABLE;
}
Copy the code

** objC_method_list: ** Stores a list of methods for the class, which can be obtained via class_copyMethodList.

The structure is as follows:

struct objc_method {
    SEL _Nonnull method_name                                 OBJC2_UNAVAILABLE;
    char * _Nullable method_types                            OBJC2_UNAVAILABLE;
    IMP _Nonnull method_imp                                  OBJC2_UNAVAILABLE;
}                                                            OBJC2_UNAVAILABLE;

struct objc_method_list {
    struct objc_method_list * _Nullable obsolete             OBJC2_UNAVAILABLE;

    int method_count                                         OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
    /* variable length structure */
    struct objc_method method_list[1]                        OBJC2_UNAVAILABLE;
}
Copy the code

** objC_PROTOCOL_LIST: ** Stores a list of protocols for classes, which can be obtained by class_copyProtocolList.

The structure is as follows:

struct objc_protocol_list {
    struct objc_protocol_list * _Nullable next;
    long count;
    __unsafe_unretained Protocol * _Nullable list[1];
};
Copy the code

2. Why design Metaclass

Metaclass represents the object of the class object, which stores the class methods of the class. Its purpose is to distinguish the instance from the list of related methods and construction information of the class, so as to facilitate each to perform their own duties and conform to the design principle of single responsibility.

In fact, there is something about object-oriented design that you can refer to in this article

3,class_copyIvarList & class_copyPropertyListThe difference between

Class_copyIvarList: gets a list of member variables of the class, i.e. variables declared in @interface{

Class_copyPropertyList: Gets a list of properties of a class, that is, properties declared via @property

4,class_rw_tclass_ro_tThe difference between

Class_rw_t: Indicates the read and write area of memory. The data stored in this area can be changed.

Class_ro_t: indicates a read-only memory area in which data cannot be changed.

The attributes, methods, and protocols that are stored in the OC object are actually stored in these two memory areas, whereas when we dynamically modify a class’s methods through the Runtime, we modify the list of methods stored in the class_rw_t area.

Refer to this article

5,categoryHow is it loaded, both categoriesloadThe loading order of methods, and the loading order of methods with the same name for both categories

Category loading occurs at runtime by adding the instance methods, properties, and protocols of the category to the class object. Add the class methods, attributes, and protocols of a category to metaclass.

The order in which the category load methods are executed is determined by the order in which the class is compiled, that is, the files in Build Phases in Xcode are loaded from top to bottom.

A category does not replace a method of the same name. If both the category and the original class have methodA, then when the category is attached, there will be two methodA methods in the class list. MethodA is added by category before methodA, so if there is a category method with the same name, the last compiled category method will be found first.

Refer to this article

6,category & extensionDifference, can I add Extension to NSObject? What’s the result?

Classification of the category:

  • Add a new method to the class
  • You cannot add member variables to a class
  • A variable defined through @property can only generate method declarations for the corresponding getter and setter, but cannot implement getter and setter methods, nor can it generate underlined member properties
  • It’s run time

Note: The reason why you can’t add attributes is that categories are determined at runtime, and the memory layout of the class is already determined at runtime. Adding instance variables will break the memory layout of the class, resulting in unexpected errors.

The extension: extension

  • You can add member variables to a class, but they are private
  • Methods can be added to a class, but they are private
  • The added properties and methods are part of the class and are determined at compile time. The @Interface in the compiler and header file and the @Implement in the implementation file together form a complete class.
  • With the creation of the class, but also with the disappearance of the class
  • Extension can be added to a class only if you have the source code of the class, so for some classes in the system, such as NSString, you cannot add class extensions

You cannot add an Extension to NSObject because methods or attributes added in Extension must be implemented in the.m file of the source class. That is, you must have the source code of a class to add an Extension to a class.

7. Message forwarding mechanism, and comparison between message forwarding mechanism and message mechanism of other languages

Message forwarding mechanism: When the receiver receives a message and cannot process the message (that is, cannot find SEL to call), the message forwarding mechanism will be started, and the process is as follows:

Phase 1: Consult the receiver and ask if it can dynamically add this method implementation

Phase 2: In phase 1, if the receiver is unable to dynamically add the method implementation, the system will ask if there are other objects that might execute the method, and if so, the system will forward it to this object for processing.

Stage 3: In the second phase, if there is no other object to handle, the system encapsulates the details of the message as an NSInvocation object and gives the receiver one last chance. If the invocation is still unavailable, the receiver will receive the doesNotRecognizeSelector method call and the program will crash.

Specific methods are as follows:

(BOOL)resolveInstanceMethod:(SEL)selector + (BOOL)resolveClassMethod:(SEL)selector // Phase 2: To ask if there are other objects can handle - (id) forwardingTargetForSelector: (SEL) selector / / the third stage - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector - (void)forwardInvocation:(NSInvocation *)invocationCopy the code

Refer to this article

8. When a method is called,Method Query -> Dynamic resolution -> Message forwardingWhat did you do

Method calls in OC, the compiled code will eventually be converted to objc_msgSend(id, SEL…). The runtime looks for SEL imPs in the cache of the isa pointer. If not, it looks for SEL IMPs in the cache. If not, it looks in method_list. If not found, _objc_msgForward(id, SEL…) is called. Forwarding the message.

9,IMP,SEL,MethodThe differences and usage scenarios

IMP: is the implementation of a method, that is, a section of C function

SEL: is the method name

Method: is a pointer of type objc_method, which is a structure as follows:

struct objc_method {
    SEL _Nonnull method_name                                 OBJC2_UNAVAILABLE;
    char * _Nullable method_types                            OBJC2_UNAVAILABLE;
    IMP _Nonnull method_imp                                  OBJC2_UNAVAILABLE;
} 
Copy the code

Usage Scenarios:

Swizzle implementation of the class will be used, through class_getInstanceMethod(class, SEL) to get the class Method, which uses SEL as the Method name

Call method_exchangeImplementations(Method1, Method2) for method exchange

We can also add methods to a Class dynamically by calling class_addMethod(Class, SEL, IMP, types), which requires us to pass an implementation of the method IMP, for example:

Static void funcName(id receiver, SEL CMD, method parameter...) {// Method specific implementation}Copy the code

The first argument to the function: the method receiver, the second argument: the method name called SEL, the corresponding argument to the method, this order is fixed.

10,load,initializeWhat’s the difference between methods? What is the difference between them in inheritance

Load: Called when the class is loaded, only once

  • Instead of using the Runtime objc_msgSend method, the function is called directly from its memory address
  • The order in which multiple classes are called depends on the order in which files in Compile Sources are called from top to bottom
  • When both a subclass and its parent implement a load method, the parent’s method is called first
  • The order in which this class and category are called is first (note: category is loaded last).
  • Multiple categories, each load will be called (which is not called with objc_msgSend), in the same order as compile Sources
  • Load is called passively, at class load time, without the need to trigger the call manually

Note: When there is an inheritance relationship between two files, the parent file is called first, and then the child file is called, regardless of whether the parent file comes before the child file or other files.

For example, compile sources files are in the following order: SubB, SubA, A, B. Load files are called in the following order: B, SubB, A, SubA.

SubB is the first class in compile Sources, so it should be called first, but SubB inherits from B, so B is called first, then SubB, then SubA, then SubA.

B, A, SubA, SubB, A load call order: B, A, SubA, SubB, here I give you A picture to sort out:

Initialize: Called the first time a class or subclass receives a message (that is, the first time a static method or instance method is called, the first time the class is used), only once

  • The call is made through the Runtime objc_msgSend method, at which point all classes have been loaded
  • Initialize is implemented by both subclasses and their parent classes. The parent class is called first, and then the subclass’s class is called
  • Initialize is implemented for this class and category at the same time. Category overwrites its own methods and only calls initialize once.
  • Initialize is called actively and only fires when the class is used for the first time

Refer to this article

Memory management

1. How does weak work? What is the structure of SideTable

Weak: it is actually a hash table structure, where key is the address of the object and value is an array of Pointers to weak. Weak refers to a weak reference, which does not count +1. When the referenced object is released, its value is automatically set to nil.

Weak implementation principle

1. Initialization: The Runtime calls the objc_initWeak function and initializes a new weak pointer to the address of the object.

2. When adding a reference: the objc_initWeak function will call objc_storeWeak(), which updates the pointer pointer and creates the corresponding weak reference table.

3. When releasing, call the clearDeallocating function. The clearDeallocating function first fetches an array of weak pointer addresses based on the object’s address, then iterates through the array to set it to nil, deletes the entry from the Weak table, and clears the object’s record.

The structure of SideTable is as follows:

Struct SideTable {// Spinlock_t slock; // Hash table RefcountMap refcnts; Weak_table_t weak_table; // Weak references the global hash table weak_table_t weak_table; }Copy the code

Refer to this article

2, the application of the associated object? How does the system implement the associative object?

Application:

  • You can add an instance variable to a class without changing the source code of the class.
  • Used in conjunction with categories, store attributes for class extensions.

Implementation principle of associated object:

The values of associated objects are actually managed by the AssociationsManager object, which contains an AssociationsHashMap static table that stores AssociationsHashMap values. The data structure of AssociationsHashMap is as follows:

AssociationsHashMap:

—— Add pointer to attribute object address (key) : ObjectAssociationMap (value: all associated value objects)

ObjectAssociationMap:

—— Key of associated value: value of associated value

Refer to this article for the implementation of runtime methods

3. How to manage memory of associated objects? How does an associated object implement the weak property?

In terms of memory management, a policy is set during assignment and operations such as retain/copy are performed on the set object according to the type of the policy.

When policy is set to OBJC_ASSOCIATION_ASSIGN, the configured association value is used for weak memory management.

This question is similar to the above question, you can refer to the article above.

4,AutoreleasepoolThe principle of? What data structures are used?

AutoreleasePoolPage An AutoreleasePoolPage consists of 4096 bytes. Each AutoreleasePoolPage is linked in a bidirectional list to form an AutoreleasePoolPage

Pop is passing in boundary objects and then sending a release message to the objects in the page

AutoreleasePool can be released in either of the following ways:

  • One is that the Autorelease object is released at the end of the current runloop iteration, and it can be released because the system adds automatic release pools of Push and Pop to each runloop iteration.
  • Manually destroy AutoreleasePool by calling the AutoreleasePool release method (drain method) or by @Autoreleasepool {}

Refer to this article