在这之前, 我们回想一下, 我们知道实现我们所需要的功能, 就要调用某些方法, 那么这些方法又是怎么样调用的呢? 原理是怎么样的? 让我们一起来探讨一下看看~~
例子:
#import上面这个例子就是我们平常所写的, 那么方法调用的原理是什么??@interface Person : NSObject- (void)test;@end@implementation Person- (void)test{ NSLog(@"调用了test方法");}@endint main(){ Person *p = [[Person alloc]init]; [p test]; return 0;}
1. 把test包装成SEL类型的数据.
2. 根据SEL数据找到对应方法的地址.
3. 根据方法地址调用对应的方法.
这就是方法调用的原理, 在我们所写的每一个方法中, 都会有相应的方法地址, 而SEL的任务就是去找对应方法的地址, 那么示意图是怎么样的呢? 让我们一起来看看:
那么根据这个, 我们就可以猜猜看, 在调用方法的时候是不是有多种方式呢, 继续往下看:
#import结果:@interface Person : NSObject- (void)test2;@end@implementation Person- (void)test2{ NSLog(@"调用了test2方法.");}@endint 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输出的结果:@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);}@endint 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结果:@interface Person : NSObject+ (void)test;- (void)test2;@end@implementation Person+ (void)test{ NSLog(@"调用了test方法.");}- (void)test2{ NSString *str = NSStringFromSelector(_cmd); NSLog(@"调用了test2方法------%@.", str);}@endint 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其实也是发送消息的一种, 原因就看上面的例子, 自己慢慢琢磨吧.
好了, 今天我们就讲到这里, 下次我们继续~~~