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

关于直接调用方法和给对象发送消息调用方法(即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
时间: 2025-01-07 07:48:43

直接调用对象方法的两种方式的相关文章

089 重用父类方法的两种方式

目录 一.直接调用指定类的方法 二.通过super()关键字 2.1 使用方法 2.2 使用super调用父类方法 2.3 super()的调用顺序 重用父类方法有两种方式: 指名道姓的使用,直接调用指定类的方法 super关键字使用 一.直接调用指定类的方法 指名道姓的使用,跟继承没有关系.但也能完成需求 class Person: school = 'xxx' def __init__(self,name,age): self.name=name self.age=age def study

C++中对象创建的两种方式

在C++中,类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* ptr=new A:这两种方式是有区别的. 静态建立一个类对象,是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象.使用这种方法,直接调用类的构造函数. 动态建立类对象,是使用new运算符将对象建立在堆空间中.这个过程分为两步,第一步是执行operator new()函数,在堆空间中搜索合适的内存并进行分配:第二步是调用构造函数构造对象,初

C++调用C代码的两种方式

由于C++支持函数重载,在编译函数代码的时候会加上参数类型的信息,而C编译只有函数名信息,导致C++直接调用C代码在链接的时候会出现函数未定义的问题.解决这种问题有两种方法.方法一:在写C代码的时候考虑到C++可能会调用这些函数,增加extern "C":方法二:如果C++要调用的C代码没有考虑到这个问题,在包含c代码的时候加上extenrn"C"的标志.例如下面有个c文件cfile.h中定义了sumOfab(int a,int b),cfile.c中实现了这个函数

【转】BAT启动执行JAVA JAR文件中的MAIN方法的两种方式

A .导出runnable jar 1. Eclipse导出选择Runnable JAR,选择执行的Main入口函数,执行 java -jar Test.jar,Jar包内包含清单文件,记录了引用到的Jar包和所需要执行的main函数所在的类  2. 如上操作会生成一个Test.jar和包含所有引用的第三方库包的Test_lib文件夹,在Jar包同级目录放入写好命令的Bat文件,执行得到 @echo offtitle test echo start exejava -jar hello.jarp

java中调用dll文件的两种方法

一中是用JNA方法,另外是用JNative方法,两种都是转载来的, JNA地址:http://blog.csdn.net/shendl/article/details/3589676   JNative地址:http://www.jb51.net/article/35232.htm JNA方法: 介绍 给大家介绍一个最新的访问本机代码的Java框架—JNA. JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架

WCF 客户端调用服务操作的两种方法

本节的主要内容:1.通过代理类的方式调用服务操作.2.通过通道的方式调用服务操作.3.代码下载 一.通过代理类的方式调用服务操作(两种方式添加代理类) 1.手动编写代理类,如下: 客户端契约: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace y.WcfFirst.Client.Proxys { [Se

在基于MVC的Web项目中使用Web API和直接连接两种方式混合式接入

在我之前介绍的混合式开发框架中,其界面是基于Winform的实现方式,后台使用Web API.WCF服务以及直接连接数据库的几种方式混合式接入,在Web项目中我们也可以采用这种方式实现混合式的接入方式,虽然Web API或者WCF方式的调用,相对直接连接数据库方式,响应效率上略差一些,不过扩展性强,也可以调动更多的设备接入,包括移动应用接入,网站接入,Winfrom客户端接入,这样可以使得服务逻辑相对独立,负责提供接口即可.这种方式中最有代表性的就是当前Web API的广泛应用,促进了各个接入端

javascript消除字符串两边空格的两种方式,面向对象和函数式编程

主要是javascript中消除字符串空格,比较两种方式的不同 //面向对象,消除字符串两边空格 String.prototype.trim = function() { return this.replace(/(^\s*)|(\s*$)/g, ""); }; //去左右空格的函数; function trim(s){ return s.replace(/(^\s*)|(\s*$)/g, ""); }调用消除空格的两种方式. var defualtPhone =

多线程实现Thread.Start()与ThreadPool.QueueUserWorkItem两种方式对比

Thread.Start(),ThreadPool.QueueUserWorkItem都是在实现多线程并行编程时常用的方法.两种方式有何异同点,而又该如何取舍? 写一个Demo,分别用两种方式实现.观察各自的现象. 一个WorkMan class,其内的method doSomething()是每次异步线程调用的方法.该方法只是随机的让线程休眠一段时间. 1 public void doSomething() 2 { 3 OnBegin(new EventArgs()); 4 5 // some