在这之前, 我们回想一下, 我们知道实现我们所需要的功能, 就要调用某些方法, 那么这些方法又是怎么样调用的呢? 原理是怎么样的? 让我们一起来探讨一下看看~~
例子:
#import <Foundation/Foundation.h>
@interface Person : NSObject
- (void)test;
@end
@implementation Person
- (void)test
{
NSLog(@"调用了test方法");
}
@end
int main()
{
Person *p = [[Person alloc]init];
[p test];
return 0;
}
上面这个例子就是我们平常所写的, 那么方法调用的原理是什么??
1. 把test包装成SEL类型的数据.
2. 根据SEL数据找到对应方法的地址.
3. 根据方法地址调用对应的方法.
这就是方法调用的原理, 在我们所写的每一个方法中, 都会有相应的方法地址, 而SEL的任务就是去找对应方法的地址, 那么示意图是怎么样的呢? 让我们一起来看看:
那么根据这个, 我们就可以猜猜看, 在调用方法的时候是不是有多种方式呢, 继续往下看:
#import <Foundation/Foundation.h>
@interface Person : NSObject
- (void)test2;
@end
@implementation Person
- (void)test2
{
NSLog(@"调用了test2方法.");
}
@end
int main()
{
Person *p = [[Person alloc]init];
[p test2];
[p performSelector:@selector(test2)];
return 0;
}
结果:
2015-01-24 21:33:08.046 09-SEL类型[830:48415] 调用了test2方法.
2015-01-24 21:33:08.047 09-SEL类型[830:48415] 调用了test2方法.
事实证明, 第二种方法也是可以的, 这种是属于间接调用, 那如果添加一个参数呢, 同样也是可以的.
#import <Foundation/Foundation.h>
@interface Person : NSObject
+ (void)test;
- (void)test2;
- (void)test3:(NSString *)str;
@end
@implementation Person
+ (void)test
{
NSLog(@"调用了test方法.");
}
- (void)test2
{
NSLog(@"调用了test2方法.");
}
- (void)test3:(NSString *)str
{
NSLog(@"test3------%@", str);
}
@end
int main()
{
Person *p = [[Person alloc]init];
[p test2];
[p performSelector:@selector(test2)];
[p performSelector:@selector(test3:) withObject:@"ABCDEFG"];
return 0;
}
输出的结果:
2015-01-24 21:35:58.273 09-SEL类型[844:49833] 调用了test2方法.
2015-01-24 21:35:58.274 09-SEL类型[844:49833] 调用了test2方法.
2015-01-24 21:35:58.274 09-SEL类型[844:49833] test3------ABCDEFG
还有几种方法, 比如把字符串转成SEL类型:
int main()
{
Person *p = [[Person alloc]init];
NSString *name = @"test2";
SEl s = NSSelectorFromString(name);
[p performSelector:s];
return 0;
}
这样子也是可以调用的.
再补充一个知识点, 其实每一个方法内部都隐藏着一个SEL的数据, 而且是系统自带的, 叫做_cmd, 下面让我们来看看:
#import <Foundation/Foundation.h>
@interface Person : NSObject
+ (void)test;
- (void)test2;
@end
@implementation Person
+ (void)test
{
NSLog(@"调用了test方法.");
}
- (void)test2
{
NSString *str = NSStringFromSelector(_cmd);
NSLog(@"调用了test2方法------%@.", str);
}
@end
int main()
{
Person *p = [[Person alloc]init];
[p test2];
return 0;
}
结果:
2015-01-24 22:10:44.445 09-SEL类型[920:59424] 调用了test2方法---test2.
看到结果之后, 我们就知道了, 在哪个方法里调用_cmd, 那么这个_cmd就指向谁, 也就是代表着当前的这个方法.
注意, 千万不要在方法里面写一句这样子的代码:
[self performSelector:_cmd];
这样子会引发死循环的, 所以千万不能这么写.
总结一下: SEL其实是对方法的一种包装, 将方法包装成一个SEL类型的数据, 去找对应的方法地址, 找到该方法的地址, 就可以调用该方法了.
其实也可以这么说, SEL其实也是发送消息的一种, 原因就看上面的例子, 自己慢慢琢磨吧.
好了, 今天我们就讲到这里, 下次我们继续~~~