前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS SEL的使用和原理?

iOS SEL的使用和原理?

作者头像
赵哥窟
发布2020-06-16 15:05:58
1.6K0
发布2020-06-16 15:05:58
举报
文章被收录于专栏:日常技术分享日常技术分享
原理

其中@selector()是取类方法的编号,取出的结果是SEL类型。

SEL:类成员方法的指针,与C的函数指针不一样,函数指针直接保存了方法的地址,而SEL只是方法的编号。

说一下C的函数指针:

代码语言:javascript
复制
int addOne(int val)
{
    return val + 1;
}
int main(int argc, char *argv[]) {
    int (*p)(int val);//定义一个函数指针
    p = addOne;//p 指向addOne的地址
    cout<<"result :"<<(*p)(5)<<endl;//直接通过函数指针调用函数
}

objective-c 中时:

代码语言:javascript
复制
SEL method = @selector(func);//定义一个类方法的指针,selector查找是当前类(包含子类)的方法

objective demo:

父类 SelectorDemo.h

代码语言:javascript
复制
#import <Foundation/Foundation.h>

@interface SelectorDemo : NSObject

@property (nonatomic, assign) SEL methodTest;

-(void)TestParentMethod;

-(void)TestChildMethod;

@end

selectorDemo.m

代码语言:javascript
复制
#import "SelectorDemo.h"

@implementation SelectorDemo

-(void)parentMethod{
    NSLog(@"parent method call success");
}

-(void)TestParentMethod{
    if (_methodTest) {
        [self performSelector:_methodTest withObject:nil];
    }
}

-(void)TestChildMethod{
    if (_methodTest) {
        [self performSelector:_methodTest withObject:nil];
    }
}

@end

子类SelectorSub.h

代码语言:javascript
复制
#import "SelectorDemo.h"

@interface SelectorSub : SelectorDemo

@end

子类SelectorSub.m

代码语言:javascript
复制
#import "SelectorSub.h"

@implementation SelectorSub

-(void)SubMethod{
    NSLog(@"sub class method call success");
}

@end

调用:

代码语言:javascript
复制
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    SelectorSub *SClass = [[SelectorSub alloc] init];
    SClass.methodTest = @selector(parentMethod);
    [SClass TestChildMethod];
    SClass.methodTest = @selector(SubMethod);
    [SClass TestParentMethod];
}

运行的结果如下:

代码语言:javascript
复制
2017-11-16 10:52:16.089 SEL方法[50141:9692483] parent method call success
2017-11-16 10:52:16.091 SEL方法[50141:9692483] sub class method call success

我们看到SClass.methodTest = @selector(parentMethod);时候子类的对象去通过@selector()方法去寻找方法的ID,这时寻找的范围包括本身和父类,我们找到方法之后将ID赋值给自身的成员变量_methodTest,之后的调用就是直接调用父类的TestChildMethod方法。 SClass.methodTest = @selector(SubMethod);通过@selector()去父类寻找方法,没有找到继续找子类的方法,找到之后继续调用,没有找到之后会报地址寻找出错。

注意:

我们在调用方法的时候,调用不属于自己的方法和调用没有定义的方法是一样的,所以需要我们验证方法是否返回消息(即是否实现这个方法),所以在不确定的时候需要respondsToSelector: 来确定方法是否定义。

SEL消息机制的工作原理:

在作为所有类的根类的NSObject 中.isa的成员变量,所以所有的对象都有一个isa的变量,而isa变量指向该对象的类。 查看NSObject的类的时候可以发现

代码语言:javascript
复制
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

在runtime.h的查看类objc_class的时候,我们可以看到一个包含isa指针的结构体。所以类也是一个对象,同时它也必须是另一个类的实例,这份类就是元类。

代码语言:javascript
复制
struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

元类同时也是一个对象,它指向的是根元类,根元类本身的isa 指针指向自己,就形成了闭环。

image

接着上面继续,所有的对象都有一个isa的变量,而isa变量指向该对象的类。类其实也是实体的存在, 程序运行时每个类都有自己的存储空间,而isa 便指向这样一个类的空间,便建立了类和对象的对应关系,类空间包含了该类的成员变量以及方法实现,还包含指向父类空间的指针。

image

方法以selector作为索引,selector的数据类型是SEL,对应每个方法的位置的ID,当我们寻找方法的时候寻找的是方法的ID,存在一个方法和ID对应的methodList表来存储这种对应关系。

selector-funName关系图:

image

编译时,编译器会通过selector来查找

代码语言:javascript
复制
[myobject funMethod1:para];

编译之后的方法应是:

代码语言:javascript
复制
objc_msgSend(myObject, 8, para);

这里的objc_msgSend()函数会使用myObject的isa指针来找到myObject放入类空间结构并在类空间结构中查找selector 8所对应的方法,如果没有找到,那么将使用指向父类的指针找到父类空间结构进行 selector 8方法的查找,如果还没有找到,就继续沿着父类网上找,直到找到,若果一直到NSObject还没有找到,就会抛异常。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • objective demo:
    • 注意:
    • SEL消息机制的工作原理:
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档