swift 有没有办法获得对任何UIButton方法选择器的泛型调用?

mxg2im7a  于 2023-01-29  发布在  Swift
关注(0)|答案(1)|浏览(133)

我最近遇到了swizzling技术。它看起来不是一个非常常用的练习,我可以理解它的缺点。但由于它是一个我们可以在swift中使用的东西,我希望我可以在操场或练习项目中拼凑一些东西。
我的想法是将swizzling用于分析目的。在这一点上,只是打印出用户实际在做什么。除了点击屏幕上的按钮,我真的想不出用户可能会做什么交互。我想,我也许可以swizzle UITapGestureRecognizer,让它运行一个跟踪点击位置的函数。等等。但这对我来说太多信息了。我只想知道按钮何时被点击。所以我认为唯一需要混合的是UIButton。但我们为UIButtons设置了选择器,或者将它们设置为IBActions
所以我的问题是,有没有一种方法可以对任何按钮的方法选择器进行泛型调用?这样,我就可以将按钮放在一个地方,让它运行分析,然后调用主函数,而无需直接更改UIViewController类中的代码。
我会张贴我的尝试,但他们相当荒谬,我不能得到任何东西,甚至运行。
有这种可能吗?

uqjltbpv

uqjltbpv1#

您可以尝试在UIControl中混合sendAction(_:to:for:)。每当每个目标-操作对发生事件时,UIControl都会调用此函数。

extension UIControl {
    // call this at an early point in your app lifecycle
    static func swizzle() {
        if let originalMethod = class_getInstanceMethod(UIControl.self, #selector(sendAction(_:to:for:))),
           let swizzledMethod = class_getInstanceMethod(UIControl.self, #selector(swizzled_sendAction)) {
            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }
    
    @objc func swizzled_sendAction(_ action: Selector,
                                   to target: Any?,
                                   for event: UIEvent?) {
        swizzled_sendAction(action, to: target, for: event)
        if self is UIButton {
            // do some analytics things
        }
    }
}

注意事项:
由于这个方法是为每个目标-动作对调用的,这意味着只有当所有按钮都有一个目标-动作对时,并且只对事件touchUpInside(一个"点击")有效,换句话说,对于每个按钮,你只调用addTarget一次,或者在情节提要中为touchUpInside添加一个连接。
如果一个按钮没有任何目标-动作对,那么点击它什么也不做。swizzled方法将不会被调用。
如果一个按钮有多个针对touchUpInside的目标-操作对,那么点击它将导致多次调用swizzled方法。
如果一个按钮有针对touchUpInside以外的事件的目标-操作对,那么触发这些事件也会导致调用swizzled方法,不过如果仔细检查UIEvent参数,在一定程度上可以防止这种情况发生。
老实说,我宁愿直接子类化UIButton,而不是swizzle。创建一个子类,在创建时做如下操作:

addTarget(self, action: #selector(doAnalytics), for: .touchUpInside)

...

@objc func doAnalytics() {
    // ...
}

相关问题