Incomprehensible Crashes? Swizzling method to the rescue!
What is the hardest thing while fixing a crash?, Of course everyone will answer “Find the root cause”
As an iOS developer, for sure you can remember one of THOSE crashes were you was ready to give up, or you try and try different solutions because you don’t know what is the root cause or you don’t have any information that may lead to reproduce or even know what is going on?. I have been there, and I think that almost every iOS Dev has been there before.
In this article I will introduce you to another tool that will help you in the analysis of those crashes that makes our lives miserable 😅.
Method Swizzling Definition
There are many definitions in internet I will stick to this one from NSHipster(1)
Method swizzling is the process of changing the implementation of an existing selector. It’s a technique made possible by the fact that method invocations in Objective-C can be changed at runtime, by changing how selectors are mapped to underlying functions in a class’s dispatch table.
Using method swizzling for crash analysis.
Ok, that’s fine but how we can use it for crashes?. Let start with a use case. We have this report in our Crash reporter tool, in this case Firebase, this is a UIKit call stack only crash
Any Ideas?
Well to be fair, we know that a view can’t add self as Subview. We also know that this crash is triggered by UINavigationController. Maybe a viewController is being pushed 2 or more times in the navigation stack?, is possible. But where should we start to search in a big application were high number of ViewControllers are continuously pushed and pop?. How do we know which viewController(s) are involved or under which circumstances is this happening?. Remember we only have this information from crash report.
Lets put some relevant log info in this crash using method swizzling
We can see here that in call stack trace line 14 we have a private method being called which is involved in the transition process and therefore the crash caused. Would be interesting to log the viewControllers stack of this UINavigationController right?. Or even under which launch conditions our Application is working.
But first be sure this is the method you need to swizzle. We can add a Xcode symbolic break point for that checking when is this function being called. Check that our Symbol name in Symbolic Breakpoint is equal to call stack trace line 14 symbol.
Then enable your new symbolic breakpoint. You now can test transitions between viewControllers handled by UINavigationController. This symbolic breakpoint should be triggered
Swizzling UINavigationController private method
We need to create an extension for UINavigationController and implement our swizzling method there.
Step by step code explanation
1- Ensure this swizzling code is executed only once
2- Get selectors to be switched
3- Ensuring that we have those selectors implemented in our instance. We get those implementations in originalMethod and swizzledMethod
4- Log if something wrong has happened
5- Exchange the implementation of both selectors
After calling this function method_exchangeImplementations
the implementations of -[UINavigationController startCustomTransition:] and [UINavigationController swizzled_startCustomTransition:] get swapped. It means that an invocation to originalMethod actually executes the code inside swizzledMethod and vice versa.
6- New swizzled method implementation. This new implementation logs stack of viewControllers and launch info
7- Invoking original -[UINavigationController startCustomTransition:]
Ok but, you are invoking same swizzled_startCustomTransition are you sure you are invoking correct selector?. Yes as we say before when we invoke swizzled_startCustomTransition we are actually invoking the non swizzled method because we have swapped their implementations in step 5
One Image worth more than 1000 words…
⚠️ Make sure you test your app and this swizzled method is executed correctly without any crash on it before releasing.
How we use it
We can use it in AppDelegate
After release
What we will be seeing in our Firebase reports after release?. Our report has changed, even we have the same crash as new one? 🤔. Don’t worry your swizzling is not creating a new crash 😜.
Now in logs tab we have more info about our crash (the info that we are adding in our swizzling method)
With this new information we now know that MyTripsHomeViewController is causing this crash. Because is being pushed 2 times or more, and now we have a better understanding of what is going on here. Even we can try to reproduce it.
Conclusion
Method Swizzling is a very powerful tool provided by the Objective-C runtime. There are many applications for it, one of them is this one. Helping to understand hard to understand crashes.
If you like it, and find this useful, please hit the clap button below 👏 to help others find it!.
References:
(2) https://medium.com/a-swift-journey/method-swizzling-swift-2f281aae189b
(3) https://medium.com/rocknnull/ios-to-swizzle-or-not-to-swizzle-f8b0ed4a1ce6
(4) https://www.innominds.com/blog/method-swizzling-in-ios-development