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

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342