【问题标题】:How to hook (swizzle) methods in Swift?如何在 Swift 中挂钩 (swizzle) 方法?
【发布时间】:2020-09-17 18:31:58
【问题描述】:

有没有什么简单的方法可以在 Swift 中挂钩(swizzle)方法?

【问题讨论】:

    标签: swift hook aspect swizzling swizzle


    【解决方案1】:

    这个框架可以提供帮助:https://github.com/623637646/SwiftHook

    如何使用

    例如,这是你的班级

    class MyObject {
        @objc dynamic func noArgsNoReturnFunc() {
        }
        @objc dynamic func sumFunc(a: Int, b: Int) -> Int {
            return a + b
        }
        @objc dynamic class func classMethodNoArgsNoReturnFunc() {
        }
    }
    

    方法@objcdynamic的关键词是必须的

    该类不必继承自 NSObject。如果类是Objective-C写的,直接hook就行了,不费吹灰之力

    1. 在执行指定实例的方法之前执行钩子关闭。
    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
    
    1. 在执行指定实例的方法后执行钩子关闭。并获取参数。
    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)是必须的

    用于挂钩beforeafter。闭包的参数必须为空或与方法相同。返回类型必须是void

    1. 完全覆盖指定实例的方法。您可以使用相同的参数或不同的参数调用 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 挂钩。闭包的第一个参数必须是与方法具有相同类型的闭包。其余参数和返回类型必须与方法相同。

    1. 在执行类的所有实例的方法之前执行钩子关闭。
    let token = try? hookBefore(targetClass: MyObject.self, selector: #selector(MyObject.noArgsNoReturnFunc)) {
        // run your code
        print("hooked!")
    }
    MyObject().noArgsNoReturnFunc()
    token?.cancelHook() // cancel the hook
    
    1. 在执行类方法之前执行钩子关闭。
    let token = try? hookClassMethodBefore(targetClass: MyObject.self, selector: #selector(MyObject.classMethodNoArgsNoReturnFunc)) {
        // run your code
        print("hooked!")
    }
    MyObject.classMethodNoArgsNoReturnFunc()
    token?.cancelHook() // cancel the hook
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-04
      • 2011-08-17
      相关资源
      最近更新 更多