其实这篇文章是对上一篇文章的补充(『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即可。
总结
结合之前的文章,综上所述,根据不同情况,使用合理的方式传入代码,能够提高程序的可读性和可维护度。
有疑问的朋友欢迎给我留言指正,或者关注我的公众号留言: