A safe, easy, powerful and efficient hook framework for iOS (Support Swift and Objective-C). https://github.com/623637646/SwiftHook
For example, this is your class
class MyObject {
    @objc dynamic func noArgsNoReturnFunc() {
    }
    @objc dynamic func sumFunc(a: Int, b: Int) -> Int {
        return a + b
    }
    @objc dynamic class func classMethodNoArgsNoReturnFunc() {
    }
}
 The key words of methods @objc and dynamic are necessary
 The class doesn't have to inherit from NSObject. If the class is written by Objective-C, Just hook it without any more effort
- Perform the hook closure before executing specified instance's method.
 
let object = MyObject()
let token = try? hookBefore(object: object, selector: #selector(MyObject.noArgsNoReturnFunc)) {
    // run your code
    print("hooked!")
}
object.noArgsNoReturnFunc()
token?.cancelHook() // cancel the hook
- Perform the hook closure after executing specified instance's method. And get the parameters.
 
let object = MyObject()
let token = try? hookAfter(object: object, selector: #selector(MyObject.sumFunc(a:b:)), closure: { a, b in
    // get the arguments of the function
    print("arg1 is \(a)") // arg1 is 3
    print("arg2 is \(b)") // arg2 is 4
    } as @convention(block) (Int, Int) -> Void)
_ = object.sumFunc(a: 3, b: 4)
token?.cancelHook() // cancel the hook
 The key word @convention(block) is necessary
 For hook at before and after. The closure's args have to be empty or the same as method. The return type has to be void
- Totally override the mehtod for specified instance. You can call original with the same parameters or different parameters. Don't even call the original method if you want.
 
let object = MyObject()
let token = try? hookInstead(object: object, selector: #selector(MyObject.sumFunc(a:b:)), closure: { original, a, b in
    // get the arguments of the function
    print("arg1 is \(a)") // arg1 is 3
    print("arg2 is \(b)") // arg2 is 4
    // run original function
    let result = original(a, b) // Or change the parameters: let result = original(-1, -2)
    print("original result is \(result)") // result = 7
    return 9
    } as @convention(block) ((Int, Int) -> Int, Int, Int) -> Int)
let result = object.sumFunc(a: 3, b: 4) // result
print("hooked result is \(result)") // result = 9
token?.cancelHook() // cancel the hook
 For hook with instead. The closure's first argument has to be a closure which has the same types with the method. The rest args and return type have to be the same as the method.
- Perform the hook closure before executing the method of all instances of the class.
 
let token = try? hookBefore(targetClass: MyObject.self, selector: #selector(MyObject.noArgsNoReturnFunc)) {
    // run your code
    print("hooked!")
}
MyObject().noArgsNoReturnFunc()
token?.cancelHook() // cancel the hook
- Perform the hook closure before executing the class method.
 
let token = try? hookClassMethodBefore(targetClass: MyObject.self, selector: #selector(MyObject.classMethodNoArgsNoReturnFunc)) {
    // run your code
    print("hooked!")
}
MyObject.classMethodNoArgsNoReturnFunc()
token?.cancelHook() // cancel the hook