You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为已遵循UIGestureRecognizerDelegate的Swift类A添加可选协议方法?

解决方案:为第三方类注入UIGestureRecognizerDelegate可选方法

为什么你的扩展方案无效?

UIGestureRecognizerDelegate是Objective-C协议,系统调用其可选方法时依赖Objective-C Runtime查找方法实现。Swift普通扩展中的方法默认不会被注册到Objective-C Runtime,因此系统无法找到你写的方法,自然不会触发断点。而子类化的方法会自动被Objective-C Runtime识别(因为UIView是Objective-C类,其子类的方法会加入Runtime方法表),所以能正常生效。

可行方案1:带@objc标记的类扩展

如果第三方类A没有实现gestureRecognizer:shouldRequireFailureOfGestureRecognizer:方法,直接给A的扩展添加@objc标记即可让方法被Objective-C Runtime识别:

extension A {
    @objc func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        print("abcd")
        // 根据需求返回对应布尔值,示例返回false
        return false
    }
}

注意:如果类A本身已经实现了这个方法,扩展中的方法不会覆盖原实现(Swift扩展方法优先级低于类自身方法),此时需要用方法交换方案。

可行方案2:方法交换(Method Swizzling)

如果类A已有该方法的实现,或者你需要确保所有A的实例(包括子类)都执行你的逻辑,可通过方法交换注入代码:

import ObjectiveC

extension A {
    private static let swizzleSetup: Void = {
        let originalSelector = #selector(UIGestureRecognizerDelegate.gestureRecognizer(_:shouldRequireFailureOf:))
        let swizzledSelector = #selector(swizzled_shouldRequireFailureOf)
        
        guard let originalMethod = class_getInstanceMethod(A.self, originalSelector),
              let swizzledMethod = class_getInstanceMethod(A.self, swizzledSelector) else {
            return
        }
        
        // 若原类未实现该方法,先添加我们的方法到原方法的selector
        let didAddMethod = class_addMethod(A.self, originalSelector,
                                          method_getImplementation(swizzledMethod),
                                          method_getTypeEncoding(swizzledMethod))
        
        if didAddMethod {
            // 替换swizzledSelector的实现为原方法(如果原方法存在的话)
            class_replaceMethod(A.self, swizzledSelector,
                               method_getImplementation(originalMethod),
                               method_getTypeEncoding(originalMethod))
        } else {
            // 原方法已存在,直接交换实现
            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }()
    
    @objc private func swizzled_shouldRequireFailureOf(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        // 先执行你的自定义逻辑
        print("abcd")
        
        // 调用原方法的实现(交换后,调用swizzled方法实际是调用原方法)
        return swizzled_shouldRequireFailureOf(gestureRecognizer, shouldRequireFailureOf: otherGestureRecognizer)
    }
}

// 在App启动时触发方法交换,比如在AppDelegate的didFinishLaunchingWithOptions中:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    _ = A.swizzleSetup
    return true
}

这种方案会修改类A的方法实现,所有继承自A的子类都会自动生效,无需重复代码。

注意事项

  • 方法交换属于Runtime黑魔法,使用前需确认第三方类A的实现细节,避免破坏原有逻辑。
  • 若使用@objc扩展方案,确保方法签名与Objective-C协议完全一致(参数、返回值类型不能错)。

内容的提问来源于stack exchange,提问作者Valentin Shamardin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:17:47