zoukankan      html  css  js  c++  java
  • NSInvocation 理解

    1、NSInvocation的作用

    封装了 方法调用对象、方法选择器、参数、返回值等,可以给对象发送一个参数大于两个的消息

    2、优势

    在 iOS 中可以直接调用某个对象的消息的方法有两种
    1:performSelector: withObject: 这种类型的方法最多只能有两个参数
    2:NSInvocation,它可以设置多个参数;


    3、使用方式

    • 通过NSObject 类生成方法签名
    • 通过方法签名生成 NSInvocation
    • 设置方法调用者
    • 设置方法选择器
    • 设置参数
    • 如果有返回值,获取返回值

    invocation代码演示

     1 // 三个参数的方法
     2 - (void)red:(NSString *)r green:(NSString *)g blue:(NSString *)b {
     3     NSLog(@"%@-%@-%@",r,g,b);
     4 }
     5 
     6 - (void)invocationInstance {
     7     // 1.通过方法调用者创建方法签名;此方法是NSObject 的方法
     8     NSMethodSignature *sig = [[self class] instanceMethodSignatureForSelector:@selector(red:green:blue:)];
     9     // 2.通过方法签名 生成NSInvocation
    10     NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
    11     // 3.对invocation设置 方法调用者
    12     invocation.target = self;
    13     // 4.对invocation设置 方法选择器
    14     invocation.selector = @selector(red:green:blue:);
    15     // 5.对invocation设置 参数
    16     NSString *r = @"ff";
    17     NSString *g = @"aa";
    18     NSString *b = @"33";
    19     // 注意:设置的参数必须从2开始;因为0和1 已经被self ,_cmd 给占用了
    20     [invocation setArgument:&r atIndex:2];
    21     [invocation setArgument:&g atIndex:3];
    22     [invocation setArgument:&b atIndex:4];
    23     // 6.执行invocation
    24     [invocation invoke];
    25     // 7.判断 方法签名 判断是否有返回值
    26     const char *sigretun = sig.methodReturnType; //方法签名的返回值
    27     NSUInteger siglength = sig.methodReturnLength; //方法签名返回值长度; 如果是字符串返回8,数字返回4,没有返回值返回0;
    28     if (siglength !=0) { //有返回值
    29         if (strcmp(sigretun, "@") == 0) {
    30             NSString *returnStr;
    31             [invocation getReturnValue:&returnStr];
    32             NSLog(@"字符串返回值:%@",returnStr);
    33         } else if (strcmp(sigretun, "i")) {
    34             int a = 0;
    35             [invocation setReturnValue:&a];
    36             NSLog(@"数字返回值:%d", a);
    37         }
    38     } else { //没有返回值
    39         NSLog(@"没有返回值");
    40     }
    41     
    42     // 8.常用方法
    43     NSUInteger argumentNum = sig.numberOfArguments;
    44     NSLog(@"%zd",argumentNum); //参数的个数
    45     
    46     const char *type = [sig getArgumentTypeAtIndex:3];
    47     NSLog(@"方法签名中下标为3的的参数类型:%s",type);
    48 }

    4performSelector 方法演示

     1 - (void)performInstanceMethod {
     2     //调用一个参数
     3     [self performSelector:@selector(oneParameter:) withObject:@"one"];
     4     
     5     //调用两个参数
     6     [self performSelector:@selector(oneParam:twoParam:) withObject:@"1" withObject:@"2"];
     7 }
     8 // 一个参数的方法
     9 - (void)oneParameter:(NSString *)one {
    10     NSLog(@"%@",one);
    11 }
    12 // 两个参数的方法
    13 - (void)oneParam:(NSString *)one twoParam:(NSString *)two {
    14     NSLog(@"one:%@-----two:%@", one, two);
    15 }

    5invocation使用场景

    在与 js 交互中,点击 webview 上某个按钮,获取网页上的一些跳转链接;例如:ml://sendMessage?red=ff&green=aa&blue=33;获取链接之后,再在 oc 中进行处理,获得方法名字符换(sendMessage:red:green:blue),并提取相应的参数值放到数组里面;将方法名字符串和参数一起放到NSInvocation中进行处理,进而调用 oc 中
    - (void)sendMessage:(NSString )r green:(NSSring)g blue:(NSString*)b;

    6常见方法及属性

    • NSInvocation
    // 保留参数,它会将所有参数和self 都retain 一遍
    - (void)retainArguments;
    // 判断参数是否存在,调用retainArguments之前,值为NO,调用之后值为YES
    @property(readonly)Bool argumentsRetained;
    • NSMethodSignature其他常用方法和属性
    // 参数个数
    @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的相关扩展

     1 #import "NSObject+Exception.h"
     2 
     3 @implementation NSObject (Exception)
     4 
     5 - (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects {
     6     
     7     //生成方法签名
     8     NSMethodSignature *sig = [NSMethodSignature methodSignatureForSelector:aSelector];
     9     if (sig == nil) { //如果方法签名不存在抛出异常
    10         [NSException raise:@"exceptionName" format:@"%@not found method",NSStringFromSelector(aSelector)];
    11     }
    12     //生成invocation
    13     NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
    14     invocation.target = self;// 设置调用对象
    15     invocation.selector = aSelector;// 设置方法选择器
    16     
    17     NSInteger num = sig.numberOfArguments - 2; // 传递进来的参数个数
    18     NSInteger min = MAX(num, objects.count); // 取得参数的数量
    19     for (int i = 0; i< min; i++) {
    20         id obj = objects[i];
    21         if ([obj isKindOfClass:[NSNull class]]) continue;
    22         // 设置参数
    23         [invocation setArgument:&obj atIndex:i + 2];
    24     }
    25     // 调用方法
    26     [invocation invoke];
    27     
    28     // 获得返回值
    29     id value = nil;
    30     if (sig.methodReturnLength !=0) { //如果有返回值的话,获取返回值
    31         [invocation getReturnValue:&value];
    32     }
    33     return value;
    34 }
    35 @end

    转自 https://www.jianshu.com/p/06b832b10283

  • 相关阅读:
    从首页看CCS布局
    Community Server专题一:概述Community Server
    datagrid程序增加列的方法
    类的关键字
    base 关键字用于从派生类中访问基类的成员:
    关于CS1.1后台管理页面的研究
    如何:创建同步 HTTP 处理程序
    Community Server专题二:体系结构
    SqlTransaction 类
    单继承与多实现
  • 原文地址:https://www.cnblogs.com/Walsh/p/13157745.html
Copyright © 2011-2022 走看看