博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[super performSelector:sel]探秘
阅读量:5133 次
发布时间:2019-06-13

本文共 2325 字,大约阅读时间需要 7 分钟。

Super

@interface Super : NSObject@end@implementation Super- (void)log{    NSLog(@"super");}@end

Child

@interface Child : Super@end@implementation Child- (void)log{    if([super respondsToSelector:@selector(log)]){        [super performSelector:@selector(log)];    }}@end

Child中的log调用能成功吗?

这种情况可能很多朋友都遇到过,在重写父类的过程中,想调用一个父类没有公开的方法,可能最省事的办法就是使用performSelector了(当然这是不好的设计方式),直觉上觉得这样当然没问题啦,可是一运行却发现代码会陷入死循环,就拿上面的例子来说会发现一直在递归调用Child里的log方法,why???

要搞清楚这个问题,还需要从runtime入手,首先,让我们来看看super是怎么回事?

让我们重写下我们的objc代码,可以看到如下的代码片段:

((id (*)(__rw_objc_super *, SEL, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Child"))}, sel_registerName("performSelector:"), sel_registerName("log"));

是的,super最终会变成对objc_msgSendSuper方法的调用,而关于objc_msgSendSuper的文档是这样写的:

/**  * Sends a message with a simple return value to the superclass of an instance of a class. *  * @param super A pointer to an \c objc_super data structure. Pass values identifying the *  context the message was sent to, including the instance of the class that is to receive the *  message and the superclass at which to start searching for the method implementation. * @param op A pointer of type SEL. Pass the selector of the method that will handle the message. * @param ... *   A variable argument list containing the arguments to the method. *  * @return The return value of the method identified by \e op. *  * @see objc_msgSend */

而它的第一个参数定义大致如下:

struct objc_super {    /// Specifies an instance of a class.    __unsafe_unretained id receiver;    /// Specifies the particular superclass of the instance to message.     __unsafe_unretained Class super_class;    /* super_class is the first class to search */};

所以,super的作用其实可以理解为两个:

  • 告诉runtime从父类开始找SEL的实现
  • 再说第二个作用之前,需要看看一个实例方法对应的IMP是什么样子的,还是看看之前重写后的Child上的log的IMP:

    static void _I_Child_log(Child * self, SEL _cmd) {...}

可见,在调用最终的c函数时,runtime会把当前实例作为第一个参数传递进去(这与很多其他面向对象的语言行为类似)。而super的第二个作用则正是要告诉runtime在执行第一步找到的IMP时self应该传什么,结合前面的内容,可以看到其实传递的就是当前的实例(这样才能保证多态)。

然后我们再来看看performSelector的实现:

- (id)performSelector:(SEL)sel {    if (!sel) [self doesNotRecognizeSelector:sel];    return ((id(*)(id, SEL))objc_msgSend)(self, sel);}

绕了一圈,[super performSelector:sel]其实就是在执行objc_msgSend(self, sel), 因此对于之前出现的现象也就不会觉得奇怪了。

转载于:https://www.cnblogs.com/MythYsJh/p/super-perform-selector.html

你可能感兴趣的文章
转载 C#文件中GetCommandLineArgs()
查看>>
list control控件的一些操作
查看>>
精读《useEffect 完全指南》
查看>>
SNF快速开发平台MVC-EasyQuery-拖拽生成SQL脚本
查看>>
DrawerLayout实现双向侧滑
查看>>
MySQL入门很简单-触发器
查看>>
LVM快照(snapshot)备份
查看>>
绝望的第四周作业
查看>>
一月流水账
查看>>
数论四大定理
查看>>
npm 常用指令
查看>>
20几个正则常用正则表达式
查看>>
TextArea中定位光标位置
查看>>
非常棒的Visual Studo调试插件:OzCode 2.0 下载地址
查看>>
判断字符串在字符串中
查看>>
hdu4374One hundred layer (DP+单调队列)
查看>>
类间关系总结
查看>>
properties配置文件读写,追加
查看>>
Linux环境下MySql安装和常见问题的解决
查看>>
lrzsz——一款好用的文件互传工具
查看>>