复制多个方法swizzles的方法IMP

我有一个类设置,理想情况下,将读取传入的任何类的方法,然后映射到单个select器在运行时,然后将它们转发到它们的原始select器。

这现在可以工作,但是我一次只能用一种方法来做。 这个问题似乎是,一旦我调整了第一种方法,我的IMP捕捉和转发方法现在已经与其他IMP方法交换。 任何进一步的尝试在这个搞砸了,因为他们使用新交换IMP来取代其他人。

1)所以我有MethodA,MethodB和CustomCatchAllMethod。

2)我将MethodA与CustomCatchAllMEthod交换。 MethodA-> CustomCatchAllMethod,CustomCatchAllMethod-> MethodA

3)现在我尝试用CustomCatchAllMethod交换到MethodB,但是现在CustomCatchAllMethod = MethodA,MethodB变成MethodA,MethodA-> MethodB。

那么如何获取/复制我想要拦截的每个新select器的IMP的新实例?

以下是上述stream程的粗略模型:

void swizzle(Class classImCopying, SEL orig){ SEL new = @selector(catchAll:); Method origMethod = class_getInstanceMethod(classImCopying, orig); Method newMethod = class_getInstanceMethod(catchAllClass,new); method_exchangeImplementations(origMethod, newMethod); } //In some method elsewhere //I want this to make both methodA and methodB point to catchAll: swizzle(someClass, @selector(methodA:)); swizzle(someClass, @selector(methodB:)); 

这种常见的方法 – 混合模式只适用于你想拦截一​​个方法。 在你的情况下,你基本上是在执行catchAll: around而不是将它插入到任何地方。

为了正确的这个,你必须使用:

 IMP imp = method_getImplementation(newMethod); method_setImplementation(origMethod, imp); 

这给你留下了一个问题:如何转发到原来的实现?
这就是使用exchangeImplementations的原始模式。

在你的情况下,你可以:

  • 保留一个原始的IMP或附近的桌子
  • 用一些常用的前缀重命名原始的方法,所以你可以从catchAll:构build一个对它们的调用catchAll:

请注意,只有当您想通过相同的方法转发所有内容时,您才能处理相同方法的方法。

你可以用块捕获原始的IMP,得到块的IMP并将其设置为方法的实现。

 Method method = class_getInstanceMethod(class, setterSelector); SEL selector = method_getName(method); IMP originalImp = method_getImplementation(method); id(^block)(id self, id arg) = ^id(id self, id arg) { return ((id(*)(id, SEL, id))originalImp)(self, selector, arg); }; IMP newImp = imp_implementationWithBlock(block); method_setImplementation(method, newImp);