『iOS概念性解说』SEL详解

其实这篇文章是对上一篇文章的补充(『iOS 概念性解说』一篇文章搞懂 Block 和 Delegate),因为SEL也是对于代码的传入,不同的是,Block 和 Delegate是代码的传入,SEL是方法的传入,Block 和 Delegate可以做回调,而SEL是用来做触发的,为什么后面会讲到。

SEL

声明

SEL s1 = @selector(test);
SEL s2 = NSSelectorFromString(@"test");

名字

NSString *str = NSStringFromSelector(@selector(test));

执行

[self performSelector:s1 ];
[self performSelector:@selector(test) ];
//带有参数的
 [test performSelector:@selector(test2:) withObject:@"param"];

判断

[self respondsToSelector:s1]

整体

上面介绍了基本语法,在这里需要整体来看一下。
我们可以建立一个Test类
Test.h

@interface Test : NSObject
//无参数的方法
- (void)test1;
//有参数的方法
- (void)test2:(NSString *)str;
// 触发
- (void)perform:(SEL)aSelector with:(NSObject*) object;
@end

Test.m

#import "Test.h"

@implementation Test
- (void)test1
{
    NSLog(@"无参数");
}

- (void)test2:(NSString *)str
{
    NSLog(@"有参数%@",str);
}
- (void)perform:(SEL)aSelector with:(NSObject*) object{
    if ([object respondsToSelector:aSelector]) {
        [object performSelector:aSelector];
    }
}
@end

有了这个类,我们可以调用一下试试看了:

#import "ViewController.h"
#import "Test.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    SEL s1 = @selector(test);
    SEL s2 = NSSelectorFromString(@"test");
   NSString *str = NSStringFromSelector(@selector(test));
    NSLog(@"%@",str);
    Test *test = [Test new];
    [test performSelector:@selector(test1)];
    [test performSelector:@selector(test2:) withObject:@"param"];
    [self performSelector:s1 ];
    [self performSelector:s2 ];
    [self performSelector:@selector(test) ];
    if ([self respondsToSelector:s1]) {
        NSLog(@"含有test方法");
    }
    if ([self respondsToSelector:@selector(test1)]) {
        NSLog(@"含有test1方法");
    }else{
        NSLog(@"不含有test1方法");
    }
    [test perform:@selector(testEnter) with:self];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
- (void)test{
    NSLog(@"test");
}
- (void)testEnter{
    NSLog(@"test inter");
}
@end

运行上述代码,可以看出,对一个类使用performSelector可以执行该类中的SEL,要注意该类需要是NSObject的子类,因为performSelector是NSObject中的方法。
在执行SEL前,我们需要确认该类中是否含有这个方法,可以使用respondsToSelector进行判断,这样更加安全一下,然后再执行。
上述代码中testEnter这个方法是传入Test类中执行的,我们通过[test perform:@selector(testEnter) with:self];传入到Test类中,我们执行了:

- (void)perform:(SEL)aSelector with:(NSObject*) object{
    if ([object respondsToSelector:aSelector]) {
        [object performSelector:aSelector];
    }
}

UIButtion的点击事件就是这样实现的。
可能有人会问,为什么SEL不能做为回调,这是由于SEL的执行是需要他的类调用performSelector,也就是我们需要将类传递进来,如果有参数,还需要传递上下文参数,这样做会增大程序的耦合性,一般不这么做。
那为什么触发可以?以UIButtion为例,我们把方法传入UIButtion,同时UIButtion本身也需要当前的ViewController。这是我们都传递进去是没有问题的,即便点击事件的方法需要传入自己作为参数也是可以的,因为这段代码本身就是在button中执行的,不用withObject,直接self即可。

总结

结合之前的文章,综上所述,根据不同情况,使用合理的方式传入代码,能够提高程序的可读性和可维护度。
有疑问的朋友欢迎给我留言指正,或者关注我的公众号留言:

《『iOS概念性解说』SEL详解》

    原文作者:mymdeep
    原文地址: https://www.jianshu.com/p/898d323c77d9
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞