What is the Runtime

Because Objc is a dynamic language, it always tries to defer some of the decision making from the compile connection to the runtime. That is, a compiler is not enough; you also need a Runtime system to execute the compiled code. This is why the Objective-C Runtime system exists, as a cornerstone of the entire Objc Runtime framework.

Runtime is a set of Runtime features provided by C, C ++, and assembly.

Runtime header file contents

File in the usr/include/objc folder of the ios SDK

List.h
NSObjCRuntime.h
NSObject.h
Object.h
Protocol.h
a.txt
hashtable.h
hashtable2.h
message.h
module.map
objc-api.h
objc-auto.h
objc-class.h
objc-exception.h
objc-load.h
objc-runtime.h
objc-sync.h
objc.h
runtime.h
Copy the code

Message.h and Runtime.h are run-time related header files where the main functions used are defined in message.h and runtime.h. Message.h mainly contains functions that send messages to objects, which is the underlying implementation of OC object method calls. Runtime.h is the run-time’s most important file, which contains the methods that operate on the runtime. Mainly includes

//runtime.h
// An opaque type that represents a method in a class definition. A type that represents a method in a class definition
typedef struct objc_method *Method;

/// An opaque type that represents an instance variable. A variable representing an instance (object)
typedef struct objc_ivar *Ivar;

/// An opaque type that represents a category. Represents a category
typedef struct objc_category *Category;

/// An opaque type that represents an Objective-C declared property. Represents an attribute declared by the OC
typedef struct objc_property *objc_property_t;

// typedeft struct objc_class *Class; // Typedeft struct objc_class *Class;
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if! __OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
Copy the code

These type definitions completely decompose a class, abstracting every part of the class definition or object into a type type, which is very convenient for manipulating class properties and methods. The properties of the OBJC2_UNAVAILABLE tag are not supported by Ojective -c 2.0, but you can actually get these properties using a function that responds to them. For example, if you want to get the name property of the Class, you can do this:

Class classPerson = Person.class;
// printf("%s\n", classPerson->name); // The name cannot be obtained with this method because OBJC2_UNAVAILABLE
const char *cname  = class_getName(classPerson);
printf("%s", cname); / / output: the Person
Copy the code

2.1 Definition of functions

Methods that operate on objects generally start with object_

Methods that operate on classes generally start with class_

Methods that operate on methods of classes or objects generally start with method_

Methods that operate on member variables generally start with ivar_

Methods that operate on properties generally start with property_

A protocol operation usually starts with protocol_

You can get an idea of the hierarchy based on the prefixes of the above functions. Methods that start with objc_ are the runtime’s ultimate steward, fetching in-memory class loading information, a list of classes, associated objects, associated properties, and so on.

For example, don’t be surprised to use runtime to print classes loaded in the current application.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    unsigned int count = 0;
    Class *classes = objc_copyClassList(&count);
    for (int i = 0; i < count; i++) {
        const char *cname = class_getName(classes[i]);
        printf("%s\n", cname); }}Copy the code

methods

First take a look at the mind map that the Runtime method looks for

In OC, the essence of a method is message sending, objc_msgSend, and we can see that methods in OC will eventually be converted by assembly code and compiled into c++ code through Clang

Objc_msgSend (id _Nullable self, SEL _Nonnull op,...)Copy the code

The receiver refers to the receiver of the message, that is, the object, and the selector is the SEL of the object.

SEL and IMP

SEL: a method pointer to a class member, different from a function pointer, just a method number IMP: a function pointer to a function we define. If we use the book analogy, SEL is the table of contents of the book, IMP is the page number of the book, and the method function is the content under the page number.

Method to find the

For example [obj foo] -> objc_msg(obj, foo)

  1. Find obj’s class using the ISA pointer to obj
  2. Find the foo method in the class’s Method list
  3. If you don’t find foo in class, keep looking for superclass
  4. Once foo is found, its implementation IMP is executed
  5. Failed to find, enter dynamic method resolution
  6. If no, enter fast forwarding
  7. Fast forwarding, return object nil, then enter the complete message forwarding process
  8. If no exception is found, throw an exception

It’s too slow, because you have to look it up every time, so you bring in objc_cache, find foo, and store foo’s method_name as key, method_IMP (function pointer) as value, structured as a hash table.

Lookup process