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
相关产品推荐
相关产品推荐

