Before Swift, in Objective-C I would swizzle or hook methods in a class using <objc/runtime.h>
.
If anyone has any info on the topic of modifying Swift's runtime and hooking functions like CydiaSubstrate and other libraries that helped in this area, please inform me.
I would like to extend the great answer provided by mbazaliy.
Another way of doing swizzling in Swift is by providing an implementation using an Objective-C block.
e.g. to replace
description
method on classNSString
we can write:This works as of Swift 1.1.
I've succeed with method swizzling in Swift. This example shows how to hook description method on NSDictionary
My implementation:
Swizzling code:
Edited: This code will work for any custom Swift class that inherits from NSObject (but will not work for classes that don't.) More examples - https://github.com/mbazaliy/MBSwizzler
After spending some time on it... Wake up this morning.... beta 6 is out and Problem Fixed in beta6! From release notes "Dynamic dispatch can now call overrides of methods and properties introduced in class extensions, fixing a regression introduced in Xcode 6 beta 5. (17985819)!"
I'm answering this question more than one year later because none of the other answers provide the definitive set of requirements for method swizzling for every kind of class.
What is described by other, while it will work flawlessly for extensions to foundation/uikit classes (like NSDictionary), will simply never work for your own Swift classes.
As described here, there is an additional requirement for method swizzling other than extending NSObject in your custom class.
The swift method you want to swizzle must be marked
dynamic
.If you don't mark it, the runtime will simply continue to call the original method instead of the swizzled one, even if the method pointers appear to have been swapped correctly.
Update:
I've expanded this answer in a blog post.
You would likely be able to swizzle swift-generated classes that inherit from Objective-C classes with no problem, since they appear to use dynamic method dispatch all the time. You may be able to swizzle methods of swift-defined classes that exist in the Objective-C runtime by virtue of being passed across the bridge, but the Objective-C side methods are likely to just be proxies back across the bridge to the swift-side runtime, so it's not clear that it'd be particularly helpful to swizzle them.
"Pure" swift method calls do not appear to be dispatched dynamically via anything like
objc_msgSend
and it appears (from brief experimentation) that the type safety of swift is implemented at compile time, and that much of the actual type information is absent (i.e. gone) at runtime for non-class types (both of which likely contribute to the purported speed advantages of swift.)For these reasons, I expect that meaningfully swizzling swift-only methods will be significantly harder than swizzling Objective-C methods, and will probably look a lot more like
mach_override
than Objective-C method swizzling.I had a Xcode 7 iOS project written in Swift 2, using Cocoapods. In a specific Cocoapod, with Objective-C source, I wanted to override a short method, without forking the pod. Writing a Swift extension wouldn't work in my case.
For using method swizzling, I created a new Objective-C class in my main bundle with the method I wanted to replace/inject into the cocoapod. (Also added the bridging header)
Using mbazaliy 's solution on stackflow, I put my code similar to this into the
didFinishLaunchingWithOptions
in my Appdelegate:This worked perfectly. The difference between @mbazaliy 's code is that I didn't need to create an instance of the
SomeClassInAPod
class first, which in my case would have been impossible.Note: I put the code in the Appdelegate because every other time the code runs, it exchanges the method for the original - it should only run one time.
I also needed to copy some assets that were referenced in the Pod's bundle to the main bundle.