1.准备测试代码:c++
#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;
}
复制代码
2.编译成.pp文件
git
clang -rewrite-objc main.m -o main.cpp
复制代码
3.打开main.cpp文件分析: 在入口
main
方法中,调用了alloc
方法和saySomething
方法,在产生的c++
代码中,都调用了objc_msgSend
这个方法,而且传了两个参数,第一个是消息的接受者(id
),第二个是方法编号(SEL
)。github
消息发送的函数定义以下:markdown
id objc_msgSend(id self, SEL _cmd, ...);
复制代码
因此他仍是能够传更多的参数的架构
4.修改函数,添加两个参数函数
#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;
}
复制代码
5.从新编译,并查看函数调用 oop
因此结论就是:方法的本质就是消息的发送测试
既然方法调用的本质就是经过objc_msgSend
发送消息,那么就用它来调用方法。ui
1.导入头文件spa
#import <objc/message.h>
复制代码
调用方法代码:
objc_msgSend(p,@selector(saySomething));
复制代码
若是报错,配置一下红框位置,请其设置为
NO
objc_msgSendSuper
定义:
OBJC_EXPORT void objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ ) 复制代码
objc_msgSendSuper
包含的头两个参数分别是结构体objc_super
和方法编号SEL
结构体objc_super
定义:
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 */
};
复制代码
包含了一个接受者receiver
和一个super_class
1.定义一个ABTeacher
继承ABPerson
,并实现doSomething
方法
@interface ABTeacher : ABPerson
-(void)doSomething;
@end
@implementation ABTeacher
-(void)doSomething
{
NSLog(@"%s",__func__);
}
@end
复制代码
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));
复制代码
ab_objc_super.super_class
是从哪一个类开始查找,若是改为ABPerson.class
,就是从ABPerson
查找,若是ABPerson
没实现就抛出异常,也不会再查找ABTeacher
。
打开objc源码找到
objc_msgSend
是在源码中汇编实现: 查看arm64
架构的
cmp p0,
:判断当前消息接收者是否为0
b.le LNilOrTagged
:若是支持tagged pointer
,走这步b.eq LReturnZero
:不支持tagged pointer
,走这步,返回0
ldr p13, [x0]
:将消息接收者isa
给p13
GetClassFromIsa_p16 p13, 1, x0
:将消息接收者的class
存到p16
GetClassFromIsa_p16
是如何经过isa
找到class
的?
由于
GetClassFromIsa_p16
p13
, 1
, x0
,因此src
是p13
也就是isa
,needs_auth
是1
执行ExtractISA
,ExtractISA
就是将isa&ISA_MASK
的结果给$0
,也就是将拿到的class
给p16
。
上面的过程就是经过消息接收者获取到class
。
(未完)
代码准备:
#import <Foundation/Foundation.h>
@protocol ABPersonDelegate <NSObject>
-(void)masterNB;
@end
@interface ABPerson : NSObject<ABPersonDelegate>
-(void)saySomething;
@end
复制代码
#import "ABPerson.h"
@implementation ABPerson
-(void)masterNB
{
NSLog(@"%s",__func__);
}
-(void)saySomething
{
NSLog(@"%s",__func__);
}
@end
复制代码
p/x ABPerson.class
:打印Class
首地址p (class_data_bits_t *)0x0000000100008868
:首地址偏移32
个字节拿到bits
并将地址强转成class_data_bits_t
类型p $1->data()
:调用class_data_bits_t
中的data()
函数p *$2
:打印data
p $3.protocols()
:调用protocols()
,获取protocol
列表p $4.list
:拿到protocol_list_t
首地址p $5.ptr
:打印protocol_list_t
首地址p *$6
:打印protocol_list_t
,发现count=1
p $7.list[0]
:打印第一个p (protocol_t *)$8
:强转成protocol_t
类型p *$9
:查看protocol_t
结构并找到 mangledName
为ABPersonDelegate
p $10.instanceMethods
:获取实例方法p $11.get(0).big()
:读取 method_list_t
中的实例方法