直接调用对象方法的两种方式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了直接调用对象方法的两种方式相关的知识,希望对你有一定的参考价值。

关于直接调用方法和给对象发送消息调用方法(即perfromSelector和NSInvocation)

 

performSelector是运行时系统负责去找方法的,在编译时候不做任何校验;如果直接调用编译是会自动校验。如果imageDownloader:didFinishWithImage:image:不存在,那么直接调用 在编译时候就能够发现(借助Xcode可以写完就发现),但是使用performSelector的话一定是在运行时候才能发现(此时程序崩溃);Cocoa支持在运行时向某个类添加方法,即方法编译时不存在,但是运行时候存在,这时候必然需要使用performSelector去调用。所以有时候如果使用了performSelector,为了程序的健壮性,会使用检查方法

- (BOOL)respondsToSelector:(SEL)aSelector;

转自 http://blog.csdn.net/meegomeego/article/details/20041887

 

1、perfromSelector

 

2、NSInvocation 

NSInvocation 比起 perfromSelector 的好处,可以传递不止两个参数

1)NSInvocation使用方式一

    //    1、创建“方法调用”对象:NSInvocation(invocation 的英文含义:调用)
    //    1>、设置“方法签名”对象,到底怎么理解这个方法签名呢???
    NSMethodSignature *signature = [ViewController instanceMethodSignatureForSelector:@selector(sendMessageWithNumber:andContent:status:)];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    //    2>、要执行谁里面的---
    invocation.target = self;
    //    3>、什么方法
    
    invocation.selector = @selector(sendMessageWithNumber:andContent:status:);
    //    4>、传递的参数
    // 注意:自定义的参数索引从2开始, 0是self /  1是_cmd;
    //      方法签名中保存的方法名称, 必须和invocation的selector中保存的方法名称一样;
    NSString *number = @"10086";
    NSString *content = @"你好";
    NSString *status = @"发送成功";
    
    [invocation setArgument:&number atIndex:2];
    [invocation setArgument:&content atIndex:3];
    [invocation setArgument:&status atIndex:4];
    
    //    2、执行调用
    [invocation invoke];

2)NSInvocation方式二:给NSObject添加一个分类

.h文件

#import <Foundation/Foundation.h>

@interface NSObject (CY)

- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects;

@end

.m文件

#import "NSObject+CY.h"

@implementation NSObject (CY)


- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects
{
    // 签名中保存了方法的名称/参数/返回值类型
    // 注意: 签名一般是用来设置参数和获取返回值的, 和方法的调用没有太大的关系
    NSMethodSignature  *signature = [[self class] instanceMethodSignatureForSelector:aSelector];
    
    // 0.判断传入的方法是否存在, 如果不存在就进行相应处理
    if (signature == nil) {
        // 如果方法不存在, 就抛出一个异常
//        @throw  [NSException exceptionWithName:@"小码哥课堂特定异常" reason:@"你太SB了" userInfo:nil];
        NSString *info = [NSString stringWithFormat:@"%@方法找不到", NSStringFromSelector(aSelector)];
        [NSException raise:@"特定异常" format:info, nil];
//        return nil;
    }
    
    // 1.创建一个NSInvocation对象
    // NSInvocation中保存了方法所属的对象/方法名称/参数/返回值
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = aSelector;
    // 注意: 如果需要通过遍历给invocation设置参数, 那么不能遍历objects数组
    // 因为objects数组的长度是不可控
    // 注意: 通过numberOfArguments方法获取的参数个数, 是包含self和_cmd的
    NSUInteger argsCount = signature.numberOfArguments - 2; // 3
    NSUInteger arrCount = objects.count; // 4  2
    NSUInteger count = MIN(argsCount, arrCount);
//    for (int i = 0; i < objects.count; i++) {
    for (int i = 0; i < count; i++) {
        id obj = objects[i];
        // 判断需要设置的参数是否是NSNull, 如果是就设置为nil
        if ([obj isKindOfClass:[NSNull class]]) {
            obj = nil;
        }
        [invocation setArgument:&obj atIndex:i + 2];
    }
    
    // 2.调用NSInvocation对象的invoke方法
    [invocation invoke];

    // 3.获取方法的返回值
    id res = nil;
    // 3.1判断当前调用的方法, 是否有返回值
//    NSLog(@"methodReturnType = %s", signature.methodReturnType);
//    NSLog(@"methodReturnLength = %zd", signature.methodReturnLength);
    if (signature.methodReturnLength != 0) {
        [invocation getReturnValue:&res];
    }
    return res;
}
@end

 

以上是关于直接调用对象方法的两种方式的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程——创建线程的两种方式

使用mybatis的两种方式

类中方法的两种调用方式

JVM -- Java内存区域HotSpot虚拟机对象探秘对象的访问定位的两种方式(句柄和直接指针两种方式)

爬虫的两种解析方式 xpath和bs4

java中多线程的两种创建方式