Nature of method

1. Prepare test code:

#import <Foundation/Foundation.h>
@interface ABPerson : NSObject- (void)saySomething;
@end
@implementation ABPerson- (void)saySomething
{
    NSLog(@"%s",__func__);
}
@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        ABPerson *p = [ABPerson alloc];
        [p saySomething];
        NSLog(@"Hello, World!");
    }
    return 0;
}

Copy the code

2. Compile to a. Pp file

clang -rewrite-objc main.m  -o main.cpp
Copy the code

3. Open the main. CPP file for analysis:At the entrancemainMethod is calledallocMethods andsaySomethingMethod in the generation ofc++In the code, all of them are calledobjc_msgSendThis method takes two arguments, the first of which is the receiver of the message.id), the second is the method number (SEL).

The message sending function is defined as follows:

id objc_msgSend(id self, SEL _cmd, ...) ;Copy the code

So he can still pass more parameters

4. Modify the function by adding two parameters

#import <Foundation/Foundation.h>
@interface ABPerson : NSObject- (void)saySomething:(NSString *)a b:(NSString *)b;
@end
@implementation ABPerson- (void)saySomething:(NSString *)a b:(NSString *)b
{
    NSLog(@"%s",__func__);
}
@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        ABPerson *p = [ABPerson alloc];
        [p saySomething:@"A" b:@"B"];
        NSLog(@"Hello, World!");
    }
    return 0;
}
Copy the code

5. Recompile and look at the function calls

So the conclusion is: the essence of a method is the sending of a message

Call the method with objc_msgSend

Since the essence of a method call is to send a message through objc_msgSend, use it to invoke the method.

1. Import the header file

#import <objc/message.h>
Copy the code

Call method code:

 objc_msgSend(p,@selector(saySomething));
Copy the code

If an error occurs, configure the position of the red box and set it toNO

Objc_msgSendSuper definition

Objc_msgSendSuper definition:

OBJC_EXPORT void
objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... * / )
Copy the code

The first two arguments contained in objc_msgSendSuper are the structure objc_super and the method number SEL

The structure objc_super defines:

struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained _Nonnull id receiver;

    /// Specifies the particular superclass of the instance to message. 
#if! defined(__cplusplus) && ! __OBJC2__
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained _Nonnull Class class;
#else
    __unsafe_unretained _Nonnull Class super_class;
#endif
    /* super_class is the first class to search */
};
Copy the code

Contains a receiver and a super_class

Objc_msgSendSuper use

1. Define an ABTeacher to inherit from ABPerson and implement doSomething

@interface ABTeacher : ABPerson- (void)doSomething;
@end
@implementation ABTeacher- (void)doSomething
{
    NSLog(@"%s",__func__);
}
@end
Copy the code
ABTeacher *t = [ABTeacher alloc];
struct objc_super ab_objc_super;
ab_objc_super.receiver = t;
ab_objc_super.super_class = ABTeacher.class;
objc_msgSendSuper(&ab_objc_super,@selector(doSomething));
Copy the code

ab_objc_super.super_classWhich class to start with, if you change toABPerson.class, it is fromABPersonFind, ifABPersonAn exception is thrown without implementation and no further search is madeABTeacher.

Objc_msgSend Assembler analysis

Open theObjc sourcefindobjc_msgSendIs in the source code assembly implementation: viewarm64The architecture of the

  • cmp p0,: Checks whether the current message receiver is0
  • b.le LNilOrTagged: If supportedtagged pointerThis step
  • b.eq LReturnZero: don’t supporttagged pointerTake this step and go back0
  • ldr p13, [x0]: Sends the message receiverisatop13
  • GetClassFromIsa_p16 p13, 1, x0: sends the message to the receiverclassenduresp16

How does GetClassFromIsa_p16 find a class from isa?

becauseGetClassFromIsa_p16 p13.1.x0, sosrcisp13That isisa.needs_authis1performExtractISA.ExtractISAIs toisa&ISA_MASKThe result of to$0That’s what you’re going to getclasstop16.

The above process is to get the class from the message receiver.

(unfinished)

supplement

Protocol analysis

Code preparation:

#import <Foundation/Foundation.h>
@protocol ABPersonDelegate <NSObject>- (void)masterNB;
@end

@interface ABPerson : NSObject<ABPersonDelegate>- (void)saySomething;
@end

Copy the code
#import "ABPerson.h"
@implementation ABPerson- (void)masterNB
{
    NSLog(@"%s",__func__); } - (void)saySomething
{
    NSLog(@"%s",__func__);
}
@end
Copy the code

  • p/x ABPerson.class: printingClassThe first address
  • p (class_data_bits_t *)0x0000000100008868: Indicates that the first address is offset32Get a bytebitsAnd force the address toclass_data_bits_ttype
  • p $1->data(): callclass_data_bits_tIn thedata()function
  • p *$2: printingdata
  • p $3.protocols() : callprotocols()To obtainprotocolThe list of
  • p $4.list: to get theprotocol_list_tThe first address
  • p $5.ptr : printingprotocol_list_tThe first address
  • p *$6 : printingprotocol_list_tAnd found thatcount=1
  • p $7.list[0]: Print the first one
  • p (protocol_t *)$8: equivalent toprotocol_ttype

  • p *$9: seeprotocol_tStructure and findmangledNameforABPersonDelegate
  • p $10.instanceMethods: Gets the instance method
  • p $11.get(0).big()Reading:method_list_tInstance methods in