Skip to content

Commit

Permalink
Reworked the swizzling code so it doesn't attempt to guess at class v…
Browse files Browse the repository at this point in the history
…s. instance and instead lets the caller be specific with what they want to do.
  • Loading branch information
bsneed committed Jun 2, 2016
1 parent c72ed90 commit 964f159
Showing 1 changed file with 57 additions and 25 deletions.
82 changes: 57 additions & 25 deletions ELFoundation/Utilities/Swizzling.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,64 @@
import Foundation

/*
For the love of pete and the Flying Spaghetti Monster...
Do not use this stuff unless you've inquired with no less than a Rabbi, a Priest,
and a Shaman... and a few other engineers to figure out if there is a better way.
*/

For the love of pete and the Flying Spaghetti Monster...
Do not use this stuff unless you've inquired with no less than a Rabbi, a Priest,
and a Shaman... and a few other engineers to figure out if there is a better way.
*/

/**
Swizzles one method for another for a class. Subsequent to executing this, whenever the `original` method is called on
the `targetClass`, the runtime will execute `replacement` instead.
- parameter targetClass: The class being targeted. For Swift class, this class must be a subclass of `NSObject`.
- parameter original: The original method being swizzled. For Swift class, this method must be marked `dynamic`.
- parameter replacement: The replacement method being swizzled. For Swift class, this method must be marked `dynamic`.
*/

public func unsafeSwizzle(targetClass: AnyObject.Type, original: Selector, replacement: Selector) {
let originalMethod = class_getInstanceMethod(targetClass, original)
let replacementMethod = class_getInstanceMethod(targetClass, replacement)

let didAddMethod = class_addMethod(targetClass, original, method_getImplementation(replacementMethod), method_getTypeEncoding(replacementMethod))
public extension NSObject {
/// Swizzles a class method on an Objective-C object.
public class func swizzleClassMethod(originalSelector: Selector, swizzledSelector:Selector) {
if let c: AnyClass = object_getClass(self) {
let originalMethod = class_getClassMethod(c, originalSelector)
let swizzledMethod = class_getClassMethod(c, swizzledSelector)

let didAddMethod = class_addMethod(c, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

if didAddMethod {
class_replaceMethod(c, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
}

if didAddMethod {
class_replaceMethod(targetClass, replacement, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, replacementMethod);
/// Swizzles an instance method on an Objective-C object.
public class func swizzleInstanceMethod(originalSelector: Selector, swizzledSelector:Selector) {
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

if didAddMethod {
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}

}


/*
Future idea:
dr_sneed [11:10 AM]
you know what would be neat?
[11:11]
a hookMethod(someSelector, options: .After) { … }
[11:11]
so i could have my block execute after someSelector is called.
[11:11]
or .Before
*/

0 comments on commit 964f159

Please sign in to comment.