message.h

message.h

概述

objc_super

/// Specifies the superclass of an instance. 
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 */
};
#endif

这里定义了一个结构体objc_super。

这个结构体里有两个实例对象,一个是id类型的receiver,一个是Class(Class的定义是在objc.h中,Class是objc_class类型的结构体,objc_class在runtime.h中)类型的super_class。

receiver其实就是self,根据注释是指定了类的实例,即自己。

super_class即父类,指定了类的父类。

这个结构体的作用是什么呢?大概猜测一下,既然放在message.h里面,应该和消息转发有关。消息转发的时候指定谁去转发消息,首先是receiver,也即时self,然后是super_class,消息也传递到了指定的父类那里。

objc_msgSend、objc_msgSendSuper

这个类里面定义了一些objc_msgSend()函数,还有objc_msgSendSuper()。

objc_msgSend这个比较常见

((void (*)(id, SEL))objc_msgSend)(p, @selector(run));

这以下的函数我们并不常见,暂时不清除他们的作用,但是查查资料可以学习学习,既然和objc_msgSend都定义在message.h中,那可能也是做消息转发用的,objc_msgSend可以发送消息,下面这些方法当然也是用来发送消息的,只是在特定的其情况下runtime使用下面一些函数进行消息转发。

正常情况下,runtime会使用函数objc_msgSend()去转发消息。当本实例没找到对应的方法时,会去父类找,如果找到了就使用objc_msgSendSuper()去转发消息,如果还是未找到方法,会使用下面的一下函数进行消息转发。


objc_msgSend_stret、objc_msgSendSuper_stret

看这个函数的文档注释,感觉不像是抛出异常才会被使用。

它应该和objc_msgSend这个是“同一级”的函数。

stret是个什么?

看了看网上有人说stret就是struct return的缩写,🤣。

那这个函数就是提供返回一个结构体的消息转发功能的函数吧。

怎么用呢?还是以Person举例:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

struct Measurements {
    CGFloat waistline;      //腰围
    CGFloat bust;           //胸围
    CGFloat hipline;        //臀围
};

typedef struct Measurements Measurements;

static inline Measurements MeasurementsMake(CGFloat waistline,CGFloat bust,CGFloat hipline){
    Measurements info;
    info.waistline = waistline;
    info.bust = bust;
    info.hipline = hipline;
    return info;
};



@interface Person : NSObject

@property (nonatomic) CGFloat height; //身高

- (Measurements)getMeasurementsInfo;

@end
#import "Person.h"

@implementation Person

- (Measurements)getMeasurementsInfo {
    return MeasurementsMake(60, 100, 100);
}

@end

在Person里我们自定义了一个存储用户三围信息的结构体Measurements,对外提供了一个获取三围信息的方法- (Measurements)getMeasurementsInfo;

那么我们使用Runtime的objc_msgSend怎么调用呢?

这个方法的返回值是一个结构体Measurements,所以我们使用objc_msgSend_stret()函数。

使用message里的函数需要先引入头文件#import <objc/message.h>

//初始化实例,直接调用方法

Person *p = [[Person alloc] init];

Measurements info = [p getMeasurementsInfo];
NSLog(@"%f,%f,%f",info.waistline,info.bust,info.hipline);

//使用objc_msgSend_stret()来发送消息

SEL sel = @selector(getMeasurementsInfo); //获取方法编号SEL
Measurements info = ((Measurements (*)(Person *, SEL, NSString*))objc_msgSend_stret)(p, sel, @"getMeasurementsInfo");
NSLog(@"%f,%f,%f",info.waistline,info.bust,info.hipline);

上面两种的调用方式是等价的,OC方法调用,最终会转成下面这种Runtime函数来做消息转发。

objc_msgSend_fpret

如果消息返回的是浮点数,使用这个函数发送消息。比如以获取身高为例:

直接获取:

CGFloat height = p.height;
//CGFloat height = [p height];

以上两种获取都是等价的,都是通过get方法获取属性。

在Runtime底层是这样进行消息转发的:

CGFloat height = ((CGFloat (*)(Person *,SEL))objc_msgSend_fpret)(p,@selector(height));

这个函数的做如下解析:

height不用说了是返回值

(Person *,SEL) 是发送方法传递的参数

Person * 表明是Person类型的实例发送消息

SEL是传递一个方法地址的SEL

(CGFloat (*)(Person *,SEL))这个整体作为函数objc_msgSend_fpret()前面部分,定义形式参数,即形参。

(p,@selector(height))作为函数后半部分,进行传实际参数,即实参。

((返回值类型 (*) (这里是形式参数其中SEL))objc_msgSend_fpret) (实参)

(*)是做什么用?是函数的标识符?


下面这三个是方法做什么用的呢?method_invoke、msgForward感觉像是做消息转发,动态消息处理用的吧。这里先放着吧,后面看能不能碰到。


method_invoke、method_invoke_stret

_objc_msgForward、_objc_msgForward_stret

objc_msgSendv、objc_msgSendv_stret

推荐阅读

第十一条理解objc_masgSend的作用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Morris_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值