美文网首页
01--方法本质02--objc_msgSend的使用

01--方法本质02--objc_msgSend的使用

作者: 修_远 | 来源:发表于2020-06-15 16:51 被阅读0次

对方法的探索,全篇分六个章节

01-方法本质-方法初探

02-方法本质-objc_msgSend的使用

03-方法本质-面试题分析

04-方法本质-lookUpImpOrForward 介绍

05-方法本质-消息查找流程

06-方法本质-消息转发流程

二、objc_msgSend方法使用

前言

本章将介绍如何在工程代码中使用 objc_msgSendobjc_msgSendSuper2 这两个方法

[toc]

2.1 环境准备

  • 创建一个 CMD 工程

  • 在 build setting 中将 Enable Strict Checking of objc_msgSend Calls 设置为 NO

    image
  • 在使用 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走位图分析


    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元类
    1. NSObject类 的元类是 NSObject元类
    2. NSObject元类 的父类是 NSObject类

2.2 objc_msgSend()

  • objc_msgSend 定义:向类的实例发送消息

    objc_msgSend(id _Nullable self,SEL _Nonnull op,。。。)
    
  • objc_msgSend 参数

    • 第一参数: 消息接受者。一个接受消息的类的实例指针
    • 第二参数: 方法编号。用来处理消息的方法编号
    • 第三参数: 不定参数。参数二中方法的参数列表
  • 对象方法

    • 第一参数: 消息接受者。对象 (SRStudent *)s
    • 第二参数: 方法编号。注册方法 sel_registerName(“方法名”)
    • 第三参数: 不定参数。参数二中方法的参数列表
    1. 调用自己的对象方法

      objc_msgSend(s,sel_registerName("invokeChildInstancMethod"));

      输出:-[SRPerson invokeChildInstancMethod]

    2. 调用父类的对象方法

      objc_msgSend(s,sel_registerName("runInstanceMethod"));

      输出:-[SRPerson runInstanceMethod]

    3. 调用自己的对象方法,一个参数

      objc_msgSend(s,sel_registerName("invokeMethodWithOne:"),@"1");

      输出:-[SRStudent invokeMethodWithOne:]-1

    4. 调用自己的对象方法,两个参数

      objc_msgSend(s,sel_registerName("invokeMethodWithOne:two:"),@"1",@"2");

      输出:-[SRStudent invokeMethodWithOne:two:]-1-2

  • 类方法

    • 第一参数: 消息接受者。类 objc_getClass("SRStudent")
    • 第二参数: 方法编号。注册方法 sel_registerName(“方法名”)
    • 第三参数: 不定参数。参数二中方法的参数列表
    1. 调用自己和父类的类方法

      objc_msgSend(objc_getClass("SRStudent"),sel_registerName("invokeChildClassMethod"));
      objc_msgSend(objc_getClass("SRStudent"),sel_registerName("runClassMethod"));
      

      输出:

      +[SRStudent invokeChildClassMethod]
      +[SRPerson runClassMethod]
      
    2. 其他场景和对象方法的调用类似,这里就不做一一验证了,读者可以自行验证。

    3. 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 对象。这个对象中的消息接受者还是本类,而不是他的父类。

相关文章

网友评论

      本文标题:01--方法本质02--objc_msgSend的使用

      本文链接:https://www.haomeiwen.com/subject/asrhxktx.html