学习程序员iOS开发资料收集区

NSInvocation 理解

2018-12-07  本文已影响5人  6d201d703e76

1、NSInvocation的作用
封装了 方法调用对象、方法选择器、参数、返回值等,可以给对象发送一个参数大于两个的消息;
2、优势
在iOS 中可以直接调用某个对象的消息的方法有两种
1:performSelector:withObject: 这种类型的方法最多只能有两个参数
2:NSInvocation,它可以设置多个参数;
3、使用方式


//三个参数的方法
-(void)take:(NSString *)name andAge:(NSString *)age andBlue:(NSString *)color{
    NSLog(@"%@-%@-%@",name,age,color);
//    return 7;
}
-(void)invocationInstance{
//    1.通过方法调用者创建方法签名;此方法是NSObject 的方法
    NSMethodSignature *sig = [[self class] instanceMethodSignatureForSelector:@selector(take:andAge:andBlue:)];
//    2.通过方法签名 生成NSInvocation
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
//    3.对invocation设置 方法调用者
    invocation.target = self;
//    4.对invocation设置 方法选择器
    invocation.selector = @selector(take:andAge:andBlue:);
//    5.对invocation设置 参数
    NSString *name = @"张三";
    NSString *age = @"20";
    NSString *color = @"red";
    //注意:设置的参数必须从2开始;因为0和1 已经被self ,_cmd 给占用了
    [invocation setArgument:&name atIndex:2];
    [invocation setArgument:&age atIndex:3];
    [invocation setArgument:&color atIndex:4];
//    6.执行invocation
    [invocation invoke];
//    7.判断 方法签名 判断是否有返回值
    const char *sigretun =  sig.methodReturnType; //方法签名的返回值
    NSUInteger siglength = sig.methodReturnLength; //方法签名返回值长度; 如果是字符串返回8,数字返回4,没有返回值返回0;
    if (siglength !=0) { //有返回值
        if (strcmp(sigretun, "@") == 0) {
            NSString *returnStr;
            [invocation getReturnValue:&returnStr];
            NSLog(@"字符串返回值:%@",returnStr);
        }else if (strcmp(sigretun, "i")){
            int a = 0;
            [invocation setReturnValue:&a];
            NSLog(@"数字返回值:%zd",a);
        }
    }else{ //没有返回值
        NSLog(@"没有返回值");
    }
    
//    8.常用方法
    NSUInteger argumentNum = sig.numberOfArguments;
    NSLog(@"%zd",argumentNum); //参数的个数
    
    const char *type = [sig getArgumentTypeAtIndex:3];
    NSLog(@"方法签名中下标为3的的参数类型:%s",type);
}

4.performSelctor 方法演示

-(void)performInstanceMethod{
    //调用一个参数
    [self performSelector:@selector(oneParameter:) withObject:@"one"];
    
    //调用两个参数
    [self performSelector:@selector(oneParameter:andAge:) withObject:@"zhangsan" withObject:@"50"];
}
//一个参数的方法
-(void)oneParameter:(NSString *)name{
    NSLog(@"%@",name);
}
//两个参数的方法
-(void)oneParameter:(NSString *)name andAge:(NSString *)age{
    NSLog(@"name:%@-----age:%@",name,age);
}

5.invocation使用场景
在与js 交互中,点击webview 上某个按钮,获取网页上的一些跳转链接;例如:ml://sendMessage_name_age_sex?name=zhangsan&age=20&sex=boy;获取链接之后,再在oc 中进行处理,获得方法名字符换(sendMessage:name:age:sex),并提取相应的参数值放到数组里面;将方法名字符串和参数一起放到NSInvocation中进行处理,进而调用oc 中
-(void)sendMessage:(NSString )name age:(NSSring)age sex:(NSString*)sex;
6.常见方法及属性

//保留参数,它会将所有参数和self 都retain 一遍
-(void)retainArguments;
//判断参数是否存在,调用retainArguments之前,值为NO,调用之后值为YES
@property(readonly)Bool argumentsRetained;
//参数个数
@property(readonly)NSUInteger numberOfArguments;
//获取方法的长度
@property(readonly)NSUInteger frameLength;
//是否是单向
-(Bool)isOneWay;
//获取方法返回值的类型
@property(readonly)const char *methodReturnType;
//获取方法返回值的长度
@property(readonly)NSUInteger methodReturnLength;
//获取指定下标的参数类型
-(const char*)getArgumentTypeArIndex:(NSUInteger)idx;
//通过c字符串获得方法签名
+(nullable MethodSignature*)signatureWithObjectCType:(const char*)types;


7.对于NSInvocation的相关扩展

#import "NSObject+Exception.h"

@implementation NSObject (Exception)
-(id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects{
    
    //生成方法签名
    NSMethodSignature *sig = [NSMethodSignature methodSignatureForSelector:aSelector];
    if (sig == nil) { //如果方法签名不存在抛出异常
        [NSException raise:@"exceptionName" format:@"%@not found method",NSStringFromSelector(aSelector)];
    }
    //生成invocation
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
    invocation.target = self;// 设置调用对象
    invocation.selector = aSelector;//设置方法选择器
    
    NSInteger num = sig.numberOfArguments -2; //传递进来的参数个数
    NSInteger min = MAX(num, objects.count); //取得参数的数量;
    for (int i = 0; i< min; i++) {
        id obj = objects[i];
        if ([obj isKindOfClass:[NSNull class]]) continue;
            //设置参数
        [invocation setArgument:&obj atIndex:i+2];
        
    }
    //调用方法
    [invocation invoke];
    
    //获得返回值
    id retrunvalue = nil;
    if (sig.methodReturnLength !=0) { //如果有返回值的话,获取返回值
        [invocation getReturnValue:&retrunvalue];
    }
    return retrunvalue;
    
    
}
@end
上一篇 下一篇

猜你喜欢

热点阅读