有没有办法让NSInvocation支持变量params函数行[NSstring stringWithFormat:..]

时间:2015-04-10 06:22:09

标签: ios objective-c reflection objective-c-runtime nsinvocation

Apple doc说" NSInvocation不支持使用可变数量的参数或联合参数调用方法。 "

我搜索了几个小时,有些人说var_list有效,但我试过,它不是

但我认为可能有一种方法可以对变量params函数做同样的事情(反射),正如我所提到的,[stringWithFormat:],

所以,我找到了一种方法,请读下面的代码。

            @interface INTObj : NSObject
    @property (nonatomic, assign)   int  realvalue
    @end

    @interface FloatObj : NSObject
    @property (nonatomic, assign)   float  realvalue
    @end

    // here ,the selectorName is only know in runtime
    NSString *selectorName = @"stringWithFormat:";
    SEL selector = NSSelectorFromString(selectorName);
    typedef id (*Obj_Imp)(id,SEL,...);
    Method md =  class_getClassMethod(obj, selector);  // here, obj means NSString
    Obj_Imp fun =  (Obj_Imp )method_getImplementation(md); // stringWithFormat:...

    NSString *arg1 = @"hello  %f  %d";

    FloatObj *fo = [[FloatObj alloc] init];
    fo.realvalue = 11.3;

    INTObj *io = [[INTObj alloc] init];
    io.realvalue = 5;


    NSObject *arr[3] = {arg1, fo,io};

   // it cracks  . exc_bad_Access code = 1
   NSString *result = fun(obj , selector, arr[0], [arr[1] realvalue],[arr[2] realvalue]) ;

   // it works but i cant do this ,because i don't know the type of the 4th parameters  at Runtime
   NSString *result = fun(obj , selector, arr[0],[(FloatObj *)arr[1] realvalue],[arr[2] realvalue])

为什么第二次调用函数" fun"在第一个裂缝时工作?

有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

这与NSInvocation无关或直接调用方法实现。如果直接调用该方法,则应该获得相同的未定义行为:

NSString *result = [NSString stringWithFormat:arr[0], [arr[1] realvalue], [arr[2] realvalue]];

甚至是常规功能:

NSLog(arr[0], [arr[1] realvalue], [arr[2] realvalue]);

在C(和Objective-C)中,每个表达式都必须具有编译时类型。编译器需要知道这种编译时类型能够正确编译代码。

那么让我问你,[arr[1] realvalue]的编译时类型应该是什么?是int吗?是float吗?编译器会根据它的类型做不同的事情。例如,如果是float,则C标准表示传递给varargs的float将被提升为double。在varargs中传递intdouble的调用约定是不同的(实际上,这两种类型具有不同的大小)。并且+[NSString stringWithFormat:]期望传递的东西的编译时类型与您在格式字符串中给出的格式说明符相匹配,否则将存在未定义的行为。

从您的格式字符串开始,您似乎希望[arr[1] realvalue]参数为floatdouble,因为您使用了%f。由于FloatObjrealvalue方法返回float的类,因此将arr[1]投射到FloatObj *似乎是正确的做法。