几个常用的回调方法

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];
}

你可能感兴趣的:(方法)