如何在 Swift 中挂钩 (swizzle) 方法?
How to hook (swizzle) methods in Swift?
在 Swift 中是否有任何简单的方法来挂钩 (swizzle) 方法?
这个框架可以帮助:https://github.com/623637646/SwiftHook
如何使用
例如,这是您的 class
class MyObject {
@objc dynamic func noArgsNoReturnFunc() {
}
@objc dynamic func sumFunc(a: Int, b: Int) -> Int {
return a + b
}
@objc dynamic class func classMethodNoArgsNoReturnFunc() {
}
}
方法@objc
和dynamic
的关键词是必须的
class 不必继承自 NSObject。如果class是Objective-C写的,hook一下就行了
- 在执行指定实例的方法之前执行钩子关闭。
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
- 执行指定实例的方法后执行钩子关闭。并获取参数。
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
需要关键词@convention(block)
挂钩 before
和 after
。闭包的参数必须为空或与方法相同。 return 类型必须是 void
- 完全覆盖指定实例的方法。您可以使用相同的参数或不同的参数调用 original。如果你愿意,甚至不要调用原始方法。
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
用instead
挂钩。闭包的第一个参数必须是一个与方法具有相同类型的闭包。其余参数和 return 类型必须与方法相同。
- 在执行class.
的所有实例的方法之前执行钩子关闭
let token = try? hookBefore(targetClass: MyObject.self, selector: #selector(MyObject.noArgsNoReturnFunc)) {
// run your code
print("hooked!")
}
MyObject().noArgsNoReturnFunc()
token?.cancelHook() // cancel the hook
- 在执行class方法之前执行钩子关闭。
let token = try? hookClassMethodBefore(targetClass: MyObject.self, selector: #selector(MyObject.classMethodNoArgsNoReturnFunc)) {
// run your code
print("hooked!")
}
MyObject.classMethodNoArgsNoReturnFunc()
token?.cancelHook() // cancel the hook
在 Swift 中是否有任何简单的方法来挂钩 (swizzle) 方法?
这个框架可以帮助:https://github.com/623637646/SwiftHook
如何使用
例如,这是您的 class
class MyObject {
@objc dynamic func noArgsNoReturnFunc() {
}
@objc dynamic func sumFunc(a: Int, b: Int) -> Int {
return a + b
}
@objc dynamic class func classMethodNoArgsNoReturnFunc() {
}
}
@objc
和dynamic
的关键词是必须的
- 在执行指定实例的方法之前执行钩子关闭。
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
- 执行指定实例的方法后执行钩子关闭。并获取参数。
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
@convention(block)
before
和 after
。闭包的参数必须为空或与方法相同。 return 类型必须是 void
- 完全覆盖指定实例的方法。您可以使用相同的参数或不同的参数调用 original。如果你愿意,甚至不要调用原始方法。
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
instead
挂钩。闭包的第一个参数必须是一个与方法具有相同类型的闭包。其余参数和 return 类型必须与方法相同。
- 在执行class. 的所有实例的方法之前执行钩子关闭
let token = try? hookBefore(targetClass: MyObject.self, selector: #selector(MyObject.noArgsNoReturnFunc)) {
// run your code
print("hooked!")
}
MyObject().noArgsNoReturnFunc()
token?.cancelHook() // cancel the hook
- 在执行class方法之前执行钩子关闭。
let token = try? hookClassMethodBefore(targetClass: MyObject.self, selector: #selector(MyObject.classMethodNoArgsNoReturnFunc)) {
// run your code
print("hooked!")
}
MyObject.classMethodNoArgsNoReturnFunc()
token?.cancelHook() // cancel the hook