『iOS概念性解说』SEL详解

作者: mymdeep | 来源:发表于2017-05-01 17:33 被阅读65次

    其实这篇文章是对上一篇文章的补充(『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详解

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