Copy the IMP method for several swizzles methods

I have a class that ideally will read the methods of any class passed in and then display all of them on the same selector at runtime before sending them to the original selector.

It works right now, but I can only do this one method at a time. The problem seems to be that as soon as I start the first method, my IMP, to catch and forward the method, has now been replaced by other IMP methods. Any further attempts to ruin this because they use the recently replaced IMP to replace others.

1) So, I have MethodA, MethodB and CustomCatchAllMethod.

2) I change the MethodA method to CustomCatchAllMEthod. MethodA-> CustomCatchAllMethod, CustomCatchAllMethod-> MethodA

3) Now I'm trying to change to MethodB using CustomCatchAllMethod, but since CustomCatchAllMethod is now = MethodA, MethodB becomes MethodA and MethodA-> MethodB.

So, how do I get / copy a new instance of my IMP for each new selector I want to intercept?

Here's a rough layout of the above thread:

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:)); 
+4
ios objective-c objective-c-runtime swizzling
source share
2 answers

This generic swizzling pattern method only works when you want to intercept one method with another. In your case, you basically move the implementation for catchAll: around, rather than catchAll: it everywhere.

To do this correctly, you will have to use:

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

This leaves you with one problem: how do I get to the original implementation?
This is what the original exchangeImplementations template used for.

In your case, you could:

  • save the source IMP table around or
  • rename the original methods using some common prefix, so you can create a call for them from catchAll:

Please note that you can only process the same methods when you want to forward everything using the same method.

+3
source share

You can capture the original IMP using the block, get the IMP block and set it as an implementation of the method.

 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); 
0
source share

All Articles