Question

I think of myself as an experienced Objective-C programmer. I do apps for a living, and use the language features to it's fullest. That includes using the runtime for varies just-in-time changes to existing frameworks. Stuff like method swizzling and dynamic subclassing really shows how this language is so much more versatile than it's other object oriented C counterpart.

But lately I've been having some thoughts about an old feature, that I still find myself in need of using from time to time, but has been deprecated for some time now. It's a replacement for the old class_setSuperClass.

I often find myself subclassing UIKit classes in order to extend them or just change their behaviour slightly. One example I came across recently was an UIScrollView subclass, that made some conditions to the panGestureRecognizer. I did that by subclassing UIScrollView and then implementing the gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:.

This had to be done this way, because you're not allowed to change the delegate of a scroll view's pan gesture recogniser (it will throw a runtime exception), and you cannot create your own custom UIScrollView panGestureRecognizer.

Now this all worked out great. I changed all usages of UIScrollView in my app to my newly created subclass, and everything worked as expected. But what about UITableView and UICollectionView which I also used throughout the app. What to do with those? As you know, both of these classes is inherited from UIScrollView, but not my custom subclass of UIScrollView. So I found myself ending up writing the same code multiple times for every class that existed (and was used in the app) that inherited from UIScrollView. Writing the same code multiple times is a programmers 1-2-3 no-go. But I did end up writing a custom subclass not only for UIScrollView but also for UITableView and UICollectionView.

Now in the old days with the class_setSuperClass you were able to "swizzle" the superclass of an already prepackaged class like UITableView. You basically just said class_setSuperClass([UITableView class], [MyScrollView class]), and everything worked out (well almost) fine. Now you had injected your own class in between UITableView and UIScrollView. So every time you did [[UITableView alloc] init] it would have the features of MyScrollView because it inherited directly from it.

Now class_setSuperClass was deprecated in iOS 2.0! Since that we could do some swizzling and hacking with the object's isa pointer. Now that has been deprecated too.

So my question is really simple. How would you approach this?

Was it helpful?

Solution

If you want to globally change a class's behavior, rather than play with class identities, the direct approach would just be to replace the method you want replaced. The runtime still allows this, with class_replaceMethod(). That seems like the simplest way to accomplish what you want here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top