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 entrancemain
Method is calledalloc
Methods andsaySomething
Method in the generation ofc++
In the code, all of them are calledobjc_msgSend
This 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_class
Which class to start with, if you change toABPerson.class
, it is fromABPerson
Find, ifABPerson
An exception is thrown without implementation and no further search is madeABTeacher
.
Objc_msgSend Assembler analysis
Open theObjc sourcefindobjc_msgSend
Is in the source code assembly implementation: viewarm64
The architecture of the
cmp p0,
: Checks whether the current message receiver is0
b.le LNilOrTagged
: If supportedtagged pointer
This stepb.eq LReturnZero
: don’t supporttagged pointer
Take this step and go back0
ldr p13, [x0]
: Sends the message receiverisa
top13
GetClassFromIsa_p16 p13, 1, x0
: sends the message to the receiverclass
enduresp16
How does GetClassFromIsa_p16 find a class from isa?
becauseGetClassFromIsa_p16
p13
.1
.x0
, sosrc
isp13
That isisa
.needs_auth
is1
performExtractISA
.ExtractISA
Is toisa&ISA_MASK
The result of to$0
That’s what you’re going to getclass
top16
.
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
: printingClass
The first addressp (class_data_bits_t *)0x0000000100008868
: Indicates that the first address is offset32
Get a bytebits
And force the address toclass_data_bits_t
typep $1->data()
: callclass_data_bits_t
In thedata()
functionp *$2
: printingdata
p $3.protocols()
: callprotocols()
To obtainprotocol
The list ofp $4.list
: to get theprotocol_list_t
The first addressp $5.ptr
: printingprotocol_list_t
The first addressp *$6
: printingprotocol_list_t
And found thatcount=1
p $7.list[0]
: Print the first onep (protocol_t *)$8
: equivalent toprotocol_t
type
p *$9
: seeprotocol_t
Structure and findmangledName
forABPersonDelegate
p $10.instanceMethods
: Gets the instance methodp $11.get(0).big()
Reading:method_list_t
Instance methods in