NSInvocation的一种用法
2013-02-16 15:52 三戒1993 阅读(103) 评论(0) 编辑 收藏 举报大家知道NSInvocation可以用来发起一次target对action的调用,还可以携带任意多的参数,它比NSObject的performSelector更为强大。。。
最近在做静态库,为了对一组类进行包装,创建了一个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 alloc] init];
sharedInstance->serviceClasses = [[NSArray alloc] initWithObjects:[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 alloc] init] autorelease];
if ([service respondsToSelector:aSelector])
{
[invocation invokeWithTarget:service];
}
}
else
{
[self doesNotRecognizeSelector:aSelector];
}
}
这样就ok了,理论上,你可以增加任意多的类,在wrapper上声名该类的同名方法,就可以使用wrapper调用该类的方法了,从而隐藏了实现类。