几个常用的回调方法
respondsToSelector与performSelector
这两个方法的优点是:
1. 与obj-c代码兼容性好。
2. 具有延迟执行特性。
3. 轻量级的回调机制。
缺点:
1. 回调产生的返回值只能为id类型,int等类型会产生错误。
2. 参数最多只能传入两个,但可以通过建立包含多个参数的类进行回避。同时返回值限制也可通过此方式解决,即建立一个输入类和一个输出类。
3. 即使在头文件里未声明该方法,也可以被调用到。
【示例1】利用respondsToSelector判断类是否实现了某方法:
Balloon.m
#import "Balloon.h" @implementation Balloon -(void) changeColor:(NSString *)color { NSLog(@"My favorite color is %@",color); } @end
ViewController.m
- (void)viewDidLoad { Balloon *balloon = [[Balloon alloc] init]; SEL changeColorFun = @selector(changeColor:); if([balloon respondsToSelector:changeColorFun]) { #pragma clang diagnostic pushs #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [balloon performSelector:changeColorFun withObject:@"blue"]; #pragma clang diagnostic pop } [super viewDidLoad]; }
respondsToSelector还有一个类似的方法instancesRespondToSelector,它用来判断类是否包含某方法或属性,可以用该方法判断iOS系统的版本是否支持某个方法或者属性。上面的判断语句也可以改成:
if([Balloon instancesRespondToSelector:changeColorFun])
【示例2】通过performSelector延迟数秒后执行某一方法:
Balloon.m
#import "Balloon.h" @implementation Balloon -(void) changeColor:(NSString *)color { NSLog(@"My favorite color is %@",color); } @end
ViewController.m
- (void)viewDidLoad { SEL myFun = NSSelectorFromString(@"changeColor:"); Balloon *balloon = [[Balloon alloc] init]; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [balloon performSelector:myFun withObject:@"green" afterDelay:5]; #pragma clang diagnostic pop [super viewDidLoad]; }
objc_msgSend
在Objective-C中,消息是直到运行的时候才和方法实现绑定的。编译器会把一个消息表达式转换成一个对消息函数objc_msgSend的调用。该函数有两个主要参数:消息接收者和消息对应的方法名字。
objc_msgSend(receiver, selector)
同时接收消息中的任意数目的参数:
objc_msgSend(receiver, selector, arg1, arg2, …)
通过导入#import <objc/message.h>获得运行时的消息调用。其定义为:
id objc_msgSend(id theReceiver, SEL theSelector, …)
优点:
1. 轻量级的回调机制。
2. 无传入参数限制。
3. 相比performSelector,使用自动引数特征时,不产生警告。
4. 同系列的方法支持double、struct等类型的返回值,但仍然不支持int类型返回值(可使用NSNumber包装以回避)。
缺点:
1. 传入不符合约定的消息时,产生副作用继续运行,而非报错。
【示例3】
User.m
#import "User.h" @implementation User -(NSString *) baseInfo:(NSString *)name from:(NSString *)city { return [NSString stringWithFormat:@"My name is %@,I come from %@",name,city]; } @end
ViewController.m
#import "ViewController.h" #import <objc/message.h> #import "User.h" @implementation ViewController - (void)viewDidLoad { User *user = [[User alloc] init]; SEL myFun = NSSelectorFromString(@"baseInfo:from:"); NSString *strReturn = objc_msgSend(user, myFun,@"tom",@"beijing"); NSLog(@"return value is :%@",strReturn); [super viewDidLoad]; }