9

I am trying to modify behaviour of a program (i dont have it's source) using SIMBL. I used class dump and found out that I need to overide an instance method

This method is in the class called controller. All I need to do is get the argument arg1 and thats it. Maybe NSLog it or post a notification... I read about method swizzling in objective-c but how can I use it?. I would need to refer to the class MessageController whose course i don't have.

Thanks!

2

2 Answers 2

35

I'm guessing you need to call the original implementation after doing your NSLog; if not, you may be able to just use a category on the class to override the method.

To swizzle the method, first you need a replacement method. I usually put something like this in a category on the target class:

- (void)replacementReceiveMessage:(const struct BInstantMessage *)arg1 {
    NSLog(@"arg1 is %@", arg1);
    [self replacementReceiveMessage:arg1];
}

This looks like it will recursively call itself, but it won't because we're going to swap things around so calling ReceiveMessage: calls this method while calling replacementReceiveMessage: calls the old version.

The second step is to use the runtime functions to actually perform the swap. The advantage of using a category is that you can use load in the category to do the work:

+ (void)load {
    SEL originalSelector = @selector(ReceiveMessage:);
    SEL overrideSelector = @selector(replacementReceiveMessage:);
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method overrideMethod = class_getInstanceMethod(self, overrideSelector);
    if (class_addMethod(self, originalSelector, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
            class_replaceMethod(self, overrideSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
            method_exchangeImplementations(originalMethod, overrideMethod);
    }
}

There are two cases that need to be handled:

  • If the method we're swizzling is actually defined in a superclass, we have to use class_addMethod to add an implementation of ReceiveMessage: to the target class, which we do using our replacement implementation. Then we can use class_replaceMethod to replace replacementReceiveMessage: with the superclass's implementation, so our new version will be able to correctly call the old.
  • If the method is defined in the target class, class_addMethod will fail but then we can use method_exchangeImplementations to just swap the new and old versions.
2
  • #import <objc/runtime.h> #import <objc/message.h>
    – bbrame
    Mar 11, 2014 at 15:13
  • If he doesn't have the source code, what are the details to actually compile and inject this code into the program ?
    – alecail
    Feb 19, 2015 at 15:52
6

The library jrswizzle handles it. Doing it yourself is not recommended, because there are a lot of details to get right. (See the table documenting the failures of previous implementations in the jrswizzle readme.)

Say you have class like this:

@interface Weh : NSObject
-(void)foo;
-(void)bar;
@end

@implementation Weh
-(void)foo {
    NSLog(@"Foo called");
}
-(void)bar {
    NSLog(@"Bar called");
    [self bar];
}
@end

You can use it like this:

Weh *weh = Weh.new;
[weh foo];
[Weh jr_swizzleMethod:@selector(foo) withMethod:@selector(bar) error:nil];
[weh foo]; 

Output:

Foo called
Bar called
Foo called
2
  • One question ....Would not calling [self bar]; inside -(void)bar make a cycle?
    – TheTiger
    May 18, 2016 at 6:32
  • 2
    @TheTiger No, because the implementation of bar, as written in Weh, has been swapped with that of foo. At runtime, foo's implementation prints Bar and calls bar, while bar's implementation simply prints Foo. That is why after the swizzle, [weh foo] prints Bar then Foo. If foo's original implementation had called foo then [weh foo] would loop forever, printing Bar then Foo then Bar ad infinitum. Jun 21, 2017 at 14:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.