The principle and use of SEL

concept

SEL: method name (number)
IMP: a function pointer that holds the address of the method
@Selector (method name) gets the number of the method, resulting in SEL type. His behavior is basically equivalent to the function pointer in C language
difference

In C language, the function name can be assigned directly to a function pointer, and the function pointer directly saves the function address
 Classes in Objc cannot directly apply function pointers, but can only be obtained by @ selector, which is the method number

Method uses @ selector as index. The data type of @ selector is SEL, which corresponds to the number of each method. When we look for a method, we use this method number. There is a methodLists in the class that stores methods to implement the mapping between IMP and sel. Method number sel finds the corresponding imp through the Dispatch table table table. Imp is a function pointer, and then executes this method.

struct objc_class {

    struct objc_class super_class;  /*Superclass*/

    const char *name;                 /*Class name*/

    long version;                   /*Version information*/

    long info;                        /*Class information*/

    long instance_size;               /*Instance size*/

    struct objc_ivar_list *ivars;     /*Instance parameter list*/

    struct objc_method_list **methodLists;  /*Method list*/

    struct objc_cache *cache;               /*Method cache*/

    struct objc_protocol_list *protocols;   /*Protocol list*/

};
typedef struct objc_method *Method;

typedef struct objc_ method {

    SEL method_name;        //Method name

    char *method_types;        //Parameter type

    IMP method_imp;            //Method implementation

};

relevant

Class returns the class of the object;

isKindOfClass and isMemberOfClass check whether the object is in the specified class inheritance system;

respondsToSelector checks whether the object can correspond to the specified message;

Conform to protocol checks whether the object implements the method of specifying protocol class;

methodForSelector returns the address of the specified method implementation.

perfor mSelector:withObject  Execute the method referred to by SEL.

Specific implementation

When looking for the address of IMP, runtime provides two methods:

IMP class_getMethodImplementation(Class cls, SEL name);
IMP method_getImplementation(Method m)

According to the official description, the first method may be faster

class_getMethodImplementation may be faster than method_getImplementation(class_getInstanceMethod(cls, name)).

(1) For the first method, both the class method and the instance method are actually called by class_getMethodImplementation() is used to find the IMP address. The difference is that the first parameter passed in is different

///Class method (suppose there is a class ClassA)
class_getMethodImplementation(objc_getMetaClass("ClassA"),@selector(methodName));

///Instance method
class_getMethodImplementation([ClassA class],@selector(methodName));

Through the different parameters passed in, different method lists are found. The structure of the following method is saved in the method list. The structure contains the implementation of the method. The selector is the name of the method in essence. Through the name of the method, the corresponding implementation can be found in the structure.

(2) For the second method, the only parameter passed in is method. The distinction between class method and instance method is to encapsulate the function of method

///Class method
Method class_getClassMethod(Class cls, SEL name)

///Instance method
Method class_getInstanceMethod(Class cls, SEL name)

///Get IMP address
IMP method_getImplementation(Method m) 

(3) , test code

@implementation TestSelAndImp

- (instancetype)init {
    self = [super init];
    if (self) {
        [self getIMPFromSelector:@selector(aaa)];
        [self getIMPFromSelector:@selector(test1)];
        [self getIMPFromSelector:@selector(test2)];
    }
    return self;
}

- (void)test1 {
    NSLog(@"test1");
}

- (void)test2 {
    NSLog(@"test2");
}

- (void)getIMPFromSelector:(SEL)aSelector {
    // First method, use 'class_getMethodImplementation'
    IMP classInstanceIMP_1 = class_getMethodImplementation(objc_getClass("TestSelAndImp"), aSelector);
    IMP metaClaseIMP_1 = class_getMethodImplementation(objc_getMetaClass("TestSelAndImp"), aSelector);
    
    // Second method, use 'method_getImplementation'
    Method classInstanceMethod_2 = class_getInstanceMethod(objc_getClass("TestSelAndImp"), aSelector);
    IMP classInstnceIMP_2 = method_getImplementation(classInstanceMethod_2);
    
    Method classMethod_2 = class_getClassMethod(objc_getClass("TestSelAndImp"), aSelector);
    IMP classIMP_2 = method_getImplementation(classMethod_2);
    
    Method metaClassMethod_2 = class_getClassMethod(objc_getMetaClass("TestSelAndImp"), aSelector);
    IMP metaClassIMP_2 = method_getImplementation(metaClassMethod_2);
    
    NSLog(@"selectorName: %@, classInstanceIMP_1: %p",NSStringFromSelector(aSelector), classInstanceIMP_1);
    NSLog(@"selectorName: %@, metaClaseIMP_1: %p",NSStringFromSelector(aSelector),metaClaseIMP_1);
    NSLog(@"selectorName: %@, classInstnceIMP_2: %p",NSStringFromSelector(aSelector),classInstnceIMP_2);
    NSLog(@"selectorName: %@, classIMP_2: %p,",NSStringFromSelector(aSelector), classIMP_2);
    NSLog(@"selectorName: %@, metaClassIMP_2: %p",NSStringFromSelector(aSelector),metaClassIMP_2);
    NSLog(@"-------");
}

@end

Print results:

Call class_ When getmethodimplementation() method is used, the same address returned by the corresponding implementation cannot be found. Whether the method is in an instance method or a class method, whether the method is called to an instance or not, the return address is the same. However, the return address is not the same each time the program is run. For another method_getImplementation() returns 0 if the corresponding implementation cannot be found.

And class_ The first parameter of getclassmethod() is passed in objc_getClass() or objc_getMetaClass(), finally calling method_getImplementation() can successfully find the implementation of class methods.

And class_ If the first parameter of getinstancemethod() is passed in objc_getMetaClass() and then call method_ When getimplementation(), the implementation of the instance method cannot be found, but the implementation of the class method can be found.

Keywords: iOS C

Added by rinjani on Fri, 26 Jun 2020 06:08:56 +0300