代码改变世界

NSInvocation的一种用法

2013-02-16 15:52  三戒1993  阅读(189)  评论(0编辑  收藏  举报

大家知道NSInvocation可以用来发起一次targetaction的调用,还可以携带任意多的参数,它比NSObjectperformSelector更为强大。。。


最近在做静态库,为了对一组类进行包装,创建了一个wrapper类,wrapper类声名了其包装类的所有接口,调用接口时,用wrapper去创建实际上工作的类实例realWorkingObject,然后调用realWorkingObject上的同名方法。


这时就遇到了问题,这组类的接口总共超过100个,wrapper类对每个接口方法实现同名的方法,这样就要实现100多个方法。。。此时的我终于体会到,编程真的是个体力活啊。。。。于是我用了2个多小时实现了这100多个接口。。我在编写的过程中,一直在想:有没有好办法能够减轻我的劳动?想过用performSelector,但它顶多接受两个对象参数,NSInvocation貌似不错,但是如何得到方法的参数列表呢,每个接口参数数量都不同,搜集参数也不是个轻松的活。


最后还是坛子上的dbs2012哥给了我启发,找到了办法,就是重写- (void)forwardInvocation:(NSInvocation *)anInvocation,这是NSObject用来在本身不能响应selector时向其他类传递调用时用到的。


我的思路是:在之前的wrapper类中,我声名所有的方法,但是一个也不实现,这样NSObject就会调用forwardInvocation,在forwardInvocation中我可以得到invocation,并将他传递到我想要调用的类实例上,下面是我的实现代码:


@interface OTSServiceWrapper : NSObject

{

    NSArray*        serviceClasses;

    Class           theRespondClass;

}

+ (OTSServiceWrapper *)sharedInstance;   // 获得单例


//...以下省略100多方法的声名。。。


@end



创建wrapper类实例时,将所有要用到的serivice类记录到数组中


#pragma mark - singleton methods

static OTSServiceWrapper *sharedInstance = nil;


+ (OTSServiceWrapper *)sharedInstance

    @synchronized(self

    { 

        if (sharedInstance == nil

        { 

            sharedInstance = [[self allocinit]; 

            sharedInstance->serviceClasses = [[NSArray allocinitWithObjects:[CentralMobileFacadeServiceclass]

                                              , [AAAService class]

                                              , [BBBService class]

                                              , [CCCService class]

                                              , [DDDService class]

                                              , [EEEService class]

                                              , [FFFService class]

                                              , [GGGService class]

                                              , [HHHService class]

                                              , [FFFService class]

                                              , [IIIService class]

                                              , [JJJService class]

                                              , [KKKService class]

                                              , [LLLService class]

                                              , [MMMService class]

                                              , [NNNService class]

                                              , [OOOService class]

                                              , nil];

        } 

    } 

    

    return sharedInstance



重写methodSignatureForSelector,找到可以响应selector的类


- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 

{

    for (Class cls in serviceClasses)

    {

        NSMethodSignature *sig = [cls instanceMethodSignatureForSelector:aSelector];

        if (sig)

        {

            theRespondClass = cls;

            return sig;

        }

    }

    

    theRespondClass = NULL;

    return nil;

}



重写forwardInvocation,对刚才找到的theRespondClass进行invocation


- (void)forwardInvocation:(NSInvocation *)invocation

{

    SEL aSelector = [invocation selector];

    

    if (theRespondClass)

    {

        id service = [[[theRespondClass allocinitautorelease];

        if ([service respondsToSelector:aSelector])

        {

            [invocation invokeWithTarget:service];

        }

    }

    else

    {

        [self doesNotRecognizeSelector:aSelector];

    }

}


这样就ok了,理论上,你可以增加任意多的类,在wrapper上声名该类的同名方法,就可以使用wrapper调用该类的方法了,从而隐藏了实现类。