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

Objective-C转Swift单元测试中带参数Method Swizzling失效问题

解决方法交换失效的问题

你的问题核心是selector匹配错误,以及Swift与Objective-C方法名转换的误解,按以下步骤修正:

1. 修正原方法的Selector获取

原Objective-C方法的SEL是pullTypesFromServer:error:,在Swift中自动转换后的方法签名为:

class func pullTypesFromServer(_ completionBlock: (Any?) -> Void, error errorBlock: MKNKErrorBlock)

所以获取原方法时,必须使用正确的selector:#selector(FNServerApiRequests.pullTypesFromServer(_:error:)),而非你之前写的pullTypes(fromServer:error:)。

2. 调整替换方法的签名

让替换方法的参数标签、类型与原方法完全对齐,确保方法签名一致:

extension FNServerApiRequests {
    @objc
    class func swizzledPullTypesFromServer(_ completionBlock: @escaping (Any?) -> Void, error errorBlock: @escaping MKNKErrorBlock) {
        print("swizzledPullTypes")
        let dic = FNTestUtils.getJsonDictionaryFile("pull-types.json")
        completionBlock(dic ?? [:]) // 用空字典避免强制解包崩溃
    }
}

注意:将Any改为Any?,匹配OC中id可以为nil的特性;同时替换强制解包为默认值,避免测试时文件不存在导致崩溃。

3. 修正交换代码

确保获取两个方法的selector完全正确,并添加空值检查避免崩溃:

func setupSwizzling() {
    guard let originalMethod = class_getClassMethod(FNServerApiRequests.self, #selector(FNServerApiRequests.pullTypesFromServer(_:error:))),
          let swizzledMethod = class_getClassMethod(FNServerApiRequests.self, #selector(FNServerApiRequests.swizzledPullTypesFromServer(_:error:))) else {
        assertionFailure("无法获取需要交换的方法,请检查方法签名")
        return
    }
    method_exchangeImplementations(originalMethod, swizzledMethod)
}

4. 确保交换时机正确

在单元测试的setUp()方法中调用setupSwizzling(),且只执行一次(避免多次交换恢复原实现):

override func setUp() {
    super.setUp()
    setupSwizzling()
}

关键原理

方法交换要求两个方法的返回值、参数类型、类/实例方法类型完全一致,同时必须通过正确的selector获取到对应的方法。Objective-C方法导入Swift时,第一个参数的外部标签会被自动省略(用_表示),这是你之前匹配错误的核心原因。

内容的提问来源于stack exchange,提问作者Glenn Posadas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 06:05:07