1

I am trying to understand how to correctly swizzle using the method_setImplementation(). So far online I have seen two predominantly popular ways to method swizzle, once is using method_setImplementation() while the other levarages method_exchangeImplementation.

When swizzling using method_exchangeImplementation() you can get into an issue where a target class does not implement the method you are trying to swizzle. To avoid problems here with an ancestor class implementing the method and incorrectly swizzling that, you first add an implementation to your target class and then swap the swizzledMethod IMP with your ancestor classes method to get things in order. This all makes perfect sense to me...

My question is how do we handle the same above case when swizzling with method_setImplementation? Do we not have to handle this case (intuitively I feel like we do) ? If we do need to handle the above case sample code would help me greatly because I am lost as to how to handle it.

Cristik
  • 30,989
  • 25
  • 91
  • 127
AyBayBay
  • 1,726
  • 4
  • 18
  • 37

1 Answers1

4

When swizzling with free functions (a.k.a regular functions), you need to take into consideration the actual method signature that the Objective-C compiler generates for the method you want swizzled, and the fact that IMP is just a function pointer, declared like this:

typedef id (*IMP)(id, SEL, ...);

Assuming you have a method named doSomethingWithObject:afterDelay:, which looks like this

- (void)doSomethingWithObject:(id)object afterDelay:(NSTimeInterval)delay

the corresponding C function that the compiler generates is (see Wikipedia for more about name mangling in Objective-C):

void _i_MyClass_doSometingWithObject_afterDelay(id self, SEL _cmd, id object, NSTimeInterval delay)

so if you want to exchange it, you need to create a similar method and pass the pointer to it:

void swizzledDoSometingWithObjectAfterDelay(id self, SEL _cmd, id object, NSTimeInterval delay) {
    // custom implementation
}

// ....
method_setImplementation(method, (IMP)swizzledDoSometingWithObjectAfterDelay);

If the method you want to swizzle might be declared in an ancestor class, and you want to swizzle it only for the child class you're interested into, you can use class_replaceMethod(), which either adds or replaces the method, and that only affects the target class:

SEL selector = @selector(doSomethingWithObject:afterDelay:);
IMP newImp = (IMP)swizzledDoSometingWithObjectAfterDelay
Method method = class_getClassMethod([MyClass class], selector);
const char * encoding = method_getTypeEncoding(method);
class_replaceMethod([MyClass class], selector, newIMP, encoding)
Cristik
  • 30,989
  • 25
  • 91
  • 127
  • Thanks for the comment. I believe I understand the logistics of how to swizzle with free functions the part I am particularly asking about is how to handle ancestry cases where the target class does not implement the function but a super class does. When swizzling via method_exchangeImplementation there is a specific way to handle this and I am asking if there is some analagous way to handle it when going through method_setImplementation.. I break it down in my question if you'd give it a read. If its not clear please do let me know I can try elaborating further.. – AyBayBay Dec 29 '15 at 08:05
  • @AyBayBay I updated the answer, let me know if the last part clarifies your question. – Cristik Dec 29 '15 at 08:38
  • thanks! I did not actually end up solving it your suggested way but I believe your suggestion should work too! – AyBayBay Dec 30 '15 at 04:11
  • So how can I add the exchange method to my swift class. As you mentioned, the exchange method should be like void swizzledDoSometingWithObjectAfterDelay(id self, SEL _cmd, id object, NSTimeInterval delay) { // custom implementation }. So the C syntax giving compilation errors. So how will I convert it to swift 3. The use of id and _cmd also giving compilation errors. – Sreekanth Nov 17 '16 at 12:11
  • @Sreekanth not sure what your problem is without having more context. I'd recommend posting a new SO question if you can't find answers to the problem within the current Swift ones, and eventually relate to this question – Cristik Nov 17 '16 at 23:30
  • Sure. I will post a new quiestion with details. – Sreekanth Nov 18 '16 at 04:17