67 lines
2.9 KiB
Swift
67 lines
2.9 KiB
Swift
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
|
|
import Foundation
|
|
|
|
class EXDevLauncherUtils {
|
|
/**
|
|
Swizzles implementations of given selectors.
|
|
*/
|
|
static func swizzle(selector selectorA: Selector, withSelector selectorB: Selector, forClass: AnyClass) {
|
|
if let methodA = class_getInstanceMethod(forClass, selectorA),
|
|
let methodB = class_getInstanceMethod(forClass, selectorB) {
|
|
let impA = method_getImplementation(methodA)
|
|
let argsTypeA = method_getTypeEncoding(methodA)
|
|
|
|
let impB = method_getImplementation(methodB)
|
|
let argsTypeB = method_getTypeEncoding(methodB)
|
|
|
|
if class_addMethod(forClass, selectorA, impB, argsTypeB) {
|
|
class_replaceMethod(forClass, selectorB, impA, argsTypeA)
|
|
} else {
|
|
method_exchangeImplementations(methodA, methodB)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Swizzles implementations of given class method selectors.
|
|
This function will backup original selector implementation for `invokeOriginalClassMethod`.
|
|
*/
|
|
static func swizzleClassMethod(selector selectorA: Selector, withSelector selectorB: Selector, forClass: AnyClass) {
|
|
if let methodA = class_getClassMethod(forClass, selectorA),
|
|
let methodB = class_getClassMethod(forClass, selectorB) {
|
|
let impA = method_getImplementation(methodA)
|
|
let backupSelectorA = NSSelectorFromString("_" + NSStringFromSelector(selectorA))
|
|
let metaClass = objc_getMetaClass(String(describing: forClass)) as? AnyClass
|
|
class_addMethod(metaClass, backupSelectorA, impA, method_getTypeEncoding(methodA))
|
|
method_setImplementation(methodA, method_getImplementation(methodB))
|
|
}
|
|
}
|
|
|
|
/**
|
|
Invokes the original implementation before swizzling for the given selector
|
|
*/
|
|
static func invokeOriginalClassMethod(selector: Selector, forClass: AnyClass) throws -> Any? {
|
|
typealias ClassMethod = @convention(c) (AnyObject, Selector) -> Any
|
|
let imp = try getOriginalClassMethodImp(selector: selector, forClass: forClass)
|
|
return unsafeBitCast(imp, to: ClassMethod.self)(self, selector)
|
|
}
|
|
|
|
/**
|
|
Invokes the original implementation before swizzling for the given selector
|
|
*/
|
|
static func invokeOriginalClassMethod(selector: Selector, forClass: AnyClass, a0: Any) throws -> Any? {
|
|
typealias ClassMethod = @convention(c) (AnyObject, Selector, Any) -> Any
|
|
let imp = try getOriginalClassMethodImp(selector: selector, forClass: forClass)
|
|
return unsafeBitCast(imp, to: ClassMethod.self)(self, selector, a0)
|
|
}
|
|
|
|
private static func getOriginalClassMethodImp(selector: Selector, forClass: AnyClass) throws -> IMP {
|
|
let backupSelector = NSSelectorFromString("_" + NSStringFromSelector(selector))
|
|
guard let method = class_getClassMethod(forClass, backupSelector) else {
|
|
fatalError("Backup selector does not exist - forClass[\(forClass)] backupSelector[\(NSStringFromSelector(backupSelector))]")
|
|
}
|
|
return method_getImplementation(method)
|
|
}
|
|
}
|