I've been writing Objective-C since the iPhone OS 2.1 days. I've watched the community swing from MVC to MVVM, flirt with ReactiveCocoa, and now apparently everyone is in love with something called VIPER which, as far as I can tell, is just MVC but with more files and a cooler name.
But today I want to talk about something different. Something that's been hiding in plain sight since NeXT workstations were cool. Something the Objective-C runtime has given us all along that we've been criminally underusing as an architectural foundation.
I'm talking about Swizzle-Driven Development, or SDD.
"If you're not swizzling, you're not really doing Objective-C. You're just writing Java with square brackets."
What Is Swizzle-Driven Development?
The core thesis is simple: the best architecture is one where you never have to change the original code. Instead, you intercept, augment, and replace behavior at runtime using method swizzling. Think of it as aspect-oriented programming, but instead of build-time weaving, you do it at +load time. Dynamically. In production.
The key insight is that in SDD, your entire application logic layer lives in categories full of swizzled methods. Your original classes remain pristine. Untouched. The business logic simply... wraps around them like a loving, imperceptible embrace.
In SDD, the golden rule is: touch nothing, change everything. Every behavior modification flows through the runtime, not the source. Your original source files become sacred artifacts, read-only monuments to your original intent.
The Core Building Block
Drop this in a category on NSObject — yes, NSObject, why would you put it anywhere else — and you're off to the races:
@implementation NSObject (SDD) + (void)swizzleMethod:(SEL)original withMethod:(SEL)swizzled { Method originalMethod = class_getInstanceMethod(self, original); Method swizzledMethod = class_getInstanceMethod(self, swizzled); // This is fine. This is always fine. method_exchangeImplementations(originalMethod, swizzledMethod); } @end
Beautiful. Now let's build an architecture on top of it.
The SDD Application Layer
In traditional MVC, your view controllers become massive 3,000-line behemoths. In SDD, there are no bloated view controllers. There's just +load.
@implementation UserProfileViewController (SDD) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ [self swizzleMethod:@selector(viewDidLoad) withMethod:@selector(sdd_viewDidLoad)]; [self swizzleMethod:@selector(purchaseButtonTapped:) withMethod:@selector(sdd_purchaseButtonTapped:)]; // Swizzle dealloc for memory tracking // (This is controversial but I stand by it) [self swizzleMethod:@selector(dealloc) withMethod:@selector(sdd_dealloc)]; }); } - (void)sdd_viewDidLoad { [self sdd_viewDidLoad]; // This calls the original. Trust me. [[SDDAnalyticsEngine sharedEngine] trackScreen:@"UserProfile"]; } // ... 847 more lines ... @end
New SDD practitioners are often confused by the recursive-looking call [self sdd_viewDidLoad] inside sdd_viewDidLoad. Don't worry — because of the swizzle, this actually calls the original viewDidLoad. This is not confusing at all once you fully internalize how swizzling works. It took me about six weeks.
Real-World Results
- Original source files: 100% unchanged ✅
- New SDD category files added: 847
- Total swizzle invocations at app launch: ~2,300
- Onboarding time for new engineers: we stopped hiring
- Senior engineers who quit: not confirmed to be related
Now if you'll excuse me, I need to go swizzle UIApplication's sendEvent: to fix a bug that I introduced by swizzling UIApplication's sendEvent:.