2012-06-02 87 views
3

我有一个facade单身,我想转发一些类的方法调用一些“静态”类。forwardInvocation而不是实例的其他类

乍一看,forwardInvocation:似乎是一个可行的解决方案,但是,NSInvocationinvokeWithTarget:setTarget:只接受一个id,我。即一个指向实例的指针,而不是一个类本身。我试着交出[MyTargetClass class]作为目标,但当我拨打[Facade someForwardedMethod]某处时,我仍然收到“没有已知类方法[...]”错误。当我打电话给[[Facade sharedInstance] someForwardedMethod]时,我得到一个“No visible @interface [...]声明选择器[...]”错误。

当然,我知道我还需要重写respondsToSelector:methodSignatureForSelector:,所以我的代码如下所示:

- (BOOL)respondsToSelector:(SEL)aSelector { 
    if ([super respondsToSelector:aSelector]) { 
     return YES; 
    } else { 
     return [MyTargetClass respondsToSelector:aSelector]; 
    } 
} 

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { 
    NSMethodSignature* signature = [super methodSignatureForSelector:selector]; 
    if (!signature) { 
     signature = [MyTargetClass methodSignatureForSelector:selector]; 
    } 
    return signature; 
} 

- (void)forwardInvocation:(NSInvocation *)anInvocation { 

    SEL aSelector = [anInvocation selector]; 

    if ([MyTargetClass respondsToSelector: aSelector]) { 
     [anInvocation invokeWithTarget:[MyTargetClass class]]; 
    } else { 
     [super forwardInvocation:anInvocation]; 
    } 
} 

有没有一种方法,使这项工作,还是我选择另一种方法?


编辑:我曾尝试罗布纳皮尔提到了他的答案是双向的,这里是我的发现:

我可以通过门面实例调用一个类的方法在我的目标类

[(id)[Facade sharedInstance] doSomethingClassyInTargetClass]; 

这比我希望的有点丑,但它的工作原理。但是,当我处理Facade类时,我无法在目标类中调用类方法。为了平息编译器,我可以写

[(Class)[Facade class] doSomethingClassyInTargetClass]; 

但随后抛出“NSInvalidArgumentException”的“[门面doSomethingClassyInTargetClass]:无法识别的选择发送到类[...]”在运行时。显然,门面类的类方法得到解决不尊重forwardInvocation:,但毕竟它有一个-在前面...

+0

我是否正确理解您正在尝试将实例调用转发给类?是否有任何理由不让你的Facade也成为单例,这样你就可以将实例调用转发给类实例和类调用? –

+0

其实这将是理想。但是,如果可能的话,将类方法调用转发给其他类就足够了。不应该用相同的代码工作吗?我试过了,但它也不起作用。我相应地修改了这个问题......我想避免实例化另一个类,它很庞大并且没有任何会从中受益的东西。 – Stefan

+2

类对象**是**实例;它是它的元类的一个实例。您可能需要使用强制转换才能说服编译器。另外,你是否尝试过新的快速转发机制'-forwardingTargetForSelector:'? –

回答

5

啊,当你添加“无可见的@interface [...]声明选择器[......]“,这一切都很清楚。

考虑一个简单的形式,只有实例方法。您可以实现-forwardInvocation:,然后你有这样的代码:

[obj doSomething]; 

现在,MyObject实际上并不要求doSomething在其头部,即使它会回应。所以编译器抱怨说这可能不起作用。该解决方法是:

[(id)obj doSomething]; 

当你声明的东西id,编译器停止检查目标是否实际实现的选择。但它也有可能是接口声明doSomething。然后编译器再次怀疑它可能是一个错字,并给你一个警告。通过“无界面”,我的意思是“没有编译器可以访问的界面”。编译器只能访问此编译单元中的接口(即.m文件及其包含的头文件)。所以你需要确保你包含定义这个选择器的头部。

现在上课,你不能使用id,但你应该能够使用Class来实现同样的事情,如:

[(Class)MyClass doSomethingClassy]; 

如果可能希望看到iOS上的RNObserverManager示例代码:PTL第4章演示了类似的东西。

你肯定也应该看看Ken Thomases提到的forwardTargetForSelector:


你不必投sharedInstanceid。只需更改签名,因为您总是希望以这种方式使用它:

+ (id)sharedInstance; 
+0

我试过了,并用我的发现修正了我的问题。并非所有工作都按我的意愿工作,但我认为这对我的目标来说已经足够了。谢谢! – Stefan

相关问题