Objective-C Runtime method swizzling in a nutshell

Objective-C gives you as a developer the ability to exchange the implementation of two methods. In other words, you can replace the implementation of one method with an implementation of another one.

 before after swizz

 

Method swizzling is a known technique in objective-c runtime to replace or extend methods in classes that you don’t own (including iOS\OSX libraries).  In essence, it modifies the mapping from method names to a method implementation as appears above.

 

If you search for method swizzling on the web, you will find a lot of articles telling you that this technique is dangerous. My take is that method swizzling, like a lot of other programming techniques,  can be risky or harmful if you don’t understand exactly what you are doing, but otherwise, it can be very useful. My advice is to be careful and understand what and how you swizzle.

 

Today, most of the mobile functional automation frameworks use swizzling techniques to implement record-replay capabilities by swizzling the sendEvent method of the UIApplication class (and other methods of different classes) so they will have control over all the incoming UIEvents of the iOS runtime.

                                                   

Before going into an example, here are some important points in my eyes:

 

  • If you decide to swizzle a method, I suggest you to do it for the whole lifetime of your application. Meaning, do it once at the beginning and keep it until your application is closed.

 

  • Following the pervious tip, the best place to swizzle methods is in the “+ (void) load” method.

And since method swizzling is hard to debug, I suggest you to add logs wherever you can.

 

  • In inheritance, method swizzling is a bit tricky.  Let’s say class B and C are derived from Class A, and class A declares method Foo1 (private, public or protected). If you swizzle Foo1 inside the load method of Class B, then each call to Foo1 (explicitly or implicitly) from Class C will execute the swizzled implementation. This is because actually you have exchanged the implementation of your base class. To bypass this issue, you need to add method Foo1 to Class B and only after that you can swizzle it.

In the example below, I will show you how to add methods at runtime and provide some best practices for swizzling. In this example, I also assume you are familiar with objective-c categories.

 

What we want to do is to log all of the UIEvents and UITouches that our application receives when the user interacts with the screen. In this case, we will swizzle sendEvent of the UIApplication class method.

 

In <objc/runtime.h> there are a few APIs that are used to swizzle methods:

1-     class_getInstanceMethod(Class cls, SEL selector);

2-     method_exchangeImplementations(SEL origin, SEL newSel);

3-     class_addMethod

(For more details about these APIs see Apple documentation)

 

Four steps and we are done:

 

  • Create a category for UIApplication class.

 

  •  Add new method swizzleMethod:

 SwizzleMethod1

 

 

Here we add the original method to “self” before swizzling in order to avoid the inheritance issue that we discussed above, and only after that we exchange implementations.

 

  • Add a new method called swizzeledSendEvent with the following implementation:

 

 swizzledSendEvent

       

There are no recursive calls in the implementation since calling swizzeledSendEvent will execute the implementation of the original sendEvent method.

              

 

  • Implement +(void) load method, and add the following code:

 

 

 load

 

 

The method swizzeledSendEvent will be triggered each time the iOS runtime calls the sendEvent method of UIApplication class. And in our implementation, we again call swizzeledSendEvent. Again, this is not a recursive call since when we call swizzeledSendEvent the implementation of the original sendEvent will be executed.

 

Now, add a breakpoint in your swizzeledSendEvent: build, run and enjoy.

 

The post was written by Ameer Tabony

Leave a Comment

We encourage you to share your comments on this post. Comments are moderated and will be reviewed
and posted as promptly as possible during regular business hours

To ensure your comment is published, be sure to follow the Community Guidelines.

Be sure to enter a unique name. You can't reuse a name that's already in use.
Be sure to enter a unique email address. You can't reuse an email address that's already in use.
Type the characters you see in the picture above.Type the words you hear.
Search
Showing results for 
Search instead for 
Do you mean 
About the Author
Featured


Follow Us
The opinions expressed above are the personal opinions of the authors, not of HP. By using this site, you accept the Terms of Use and Rules of Participation.