对方法的探索,全篇分六个章节
二、objc_msgSend方法使用
前言
本章将介绍如何在工程代码中使用
objc_msgSend
和objc_msgSendSuper2
这两个方法
[toc]
2.1 环境准备
创建一个 CMD 工程
-
在 build setting 中将
Enable Strict Checking of objc_msgSend Calls
设置为NO
在使用
objc_msgSend
的地方 导入头文件#import <objc/Message。h>
-
SRPerson : NSObject
@interface SRPerson : NSObject - (void)runInstanceMethod; + (void)runClassMethod; @end
-
SRStudent : SRPerson
@interface SRStudent : SRPerson - (void)invokeChildInstancMethod; + (void)invokeChildClassMethod; - (void)invokeMethodWithOne:(id)one; - (void)invokeMethodWithOne:(id)one two:(id)two; @end
-
isa走位图分析
- superclass:self.superclass
- isa:self.class/[s class]/object_getClass([s class])
OC对象分为三种:
- 实例对象(instance对象)
- 类对象(class对象)
- 元类对象(meta-class对象)
这个走位图中有个地方需要注意: 右上角的走位
-
Root class(class)
: 根父类 -NSObject类
-
Root class(meta)
: 根元类 -NSObject元类
-
NSObject类
的元类是NSObject元类
-
NSObject元类
的父类是NSObject类
2.2 objc_msgSend()
-
objc_msgSend 定义:向类的实例发送消息
objc_msgSend(id _Nullable self,SEL _Nonnull op,。。。)
-
objc_msgSend 参数
- 第一参数: 消息接受者。一个接受消息的类的实例指针
- 第二参数: 方法编号。用来处理消息的方法编号
- 第三参数: 不定参数。参数二中方法的参数列表
-
对象方法
- 第一参数: 消息接受者。对象 (SRStudent *)s
- 第二参数: 方法编号。注册方法 sel_registerName(“方法名”)
- 第三参数: 不定参数。参数二中方法的参数列表
-
调用自己的对象方法
objc_msgSend(s,sel_registerName("invokeChildInstancMethod"));
输出:
-[SRPerson invokeChildInstancMethod]
-
调用父类的对象方法
objc_msgSend(s,sel_registerName("runInstanceMethod"));
输出:
-[SRPerson runInstanceMethod]
-
调用自己的对象方法,一个参数
objc_msgSend(s,sel_registerName("invokeMethodWithOne:"),@"1");
输出:
-[SRStudent invokeMethodWithOne:]-1
-
调用自己的对象方法,两个参数
objc_msgSend(s,sel_registerName("invokeMethodWithOne:two:"),@"1",@"2");
输出:
-[SRStudent invokeMethodWithOne:two:]-1-2
-
类方法
- 第一参数: 消息接受者。类
objc_getClass("SRStudent")
- 第二参数: 方法编号。注册方法 sel_registerName(“方法名”)
- 第三参数: 不定参数。参数二中方法的参数列表
-
调用自己和父类的类方法
objc_msgSend(objc_getClass("SRStudent"),sel_registerName("invokeChildClassMethod")); objc_msgSend(objc_getClass("SRStudent"),sel_registerName("runClassMethod"));
输出:
+[SRStudent invokeChildClassMethod] +[SRPerson runClassMethod]
其他场景和对象方法的调用类似,这里就不做一一验证了,读者可以自行验证。
-
从
isa走位图
中可以知道类方法是存在元类实例里面的实例方法列表,而元类实例的根根父类为 NSObject,所以子类的类方法可以访问 NSObject的实例方法。-
创建一个NSObject的分类
@interface NSObject (SR) - (void)invokeNSObjectInstanceMethod; @end
-
通过类方法调用
objc_msgSend(objc_getClass("SRStudent"),sel_registerName("invokeNSObjectInstanceMethod"));
输出:
-[NSObject(SR) invokeNSObjectInstanceMethod]
-
- 第一参数: 消息接受者。类
2.3 objc_msgSendSuper()
-
objc_msgSendSuper 定义:向类实例的超类发送消息。
objc_msgSend(id _Nullable self,SEL _Nonnull op,。。。)
-
objc_msgSendSuper 参数
第一参数: 消息接受者。
objc_super
对象第二参数: 方法编号。用来处理消息的方法编号
第三参数: 不定参数。参数二中方法的参数列表
-
struct objc_super
struct objc_super { __unsafe_unretained _Nonnull id receiver; __unsafe_unretained _Nonnull Class super_class; };
第一个参数:消息接受者。消息接受者还是自己,这个很重要,一定要记住
第二个参数:父类
-
创建一个
objc_super
对象的父类结构体变量sr_super
struct objc_super sr_obj_super; sr_obj_super.receiver = s; sr_obj_super.super_class = class_getSuperclass(SRStudent。class);
-
创建一个
objc_super
类的父类结构体变量sr_super
struct objc_super sr_class_super; sr_class_super.receiver = SRStudent。class; sr_class_super.super_class = class_getSuperclass(object_getClass(SRStudent。class));
-
方法调用
objc_msgSendSuper(&sr_obj_super,sel_registerName("runInstanceMethod")); objc_msgSendSuper(&sr_class_super,sel_registerName("runClassMethod"));
输出:
-[SRPerson runInstanceMethod] +[SRPerson runClassMethod]
其他更多的方法调用的过程这里就不做分析了,基本上和第一例子中的方法调用都是一样,在
objc_msgSendSuper
这个方法中,最重要的就是理解第一个参数objc_super
对象。这个对象中的消息接受者还是本类,而不是他的父类。