如何在嵌套非可抛出闭包中调用throw?Swift闭包类型转换报错处理
我明白你的痛点——你想保留闭包的抛出能力,但Swift的类型系统卡着不让你直接转换,而且还不能修改getOptionalConfigurations函数本身。好在你提到可以修改Objective-C端的方法签名(添加NS_SWIFT相关标识),这刚好是解决问题的关键!
优先方案:修改Objective-C方法签名,让Swift生成抛出闭包类型
这个方案能完美保留你想要的抛出能力,步骤很简单:
1. 调整Objective-C端的方法定义
找到对应getOptionalConfigurations的Objective-C方法,它的completion handler参数应该是类似这样的:
- (void)getOptionalConfigurationsWithCompletion:(void (^)(NSArray<NSString *> * _Nullable, NSError * _Nullable))completion;
你只需要给这个方法加上NS_SWIFT_THROWS_ON_ERROR宏,修改后变成:
- (void)getOptionalConfigurationsWithCompletion:(void (^)(NSArray<NSString *> * _Nullable, NSError * _Nullable))completion NS_SWIFT_THROWS_ON_ERROR;
2. 在Swift中直接使用抛出闭包
添加这个宏后,Swift编译器会自动把该方法的completion类型推断为([String]?) throws -> Void——原来的Error?参数会被Swift自动处理成抛出逻辑,你不需要再手动传递错误参数。这时候你直接把你的抛出函数传进去,就不会再出现类型不匹配的错误了!
为什么这能行?
NS_SWIFT_THROWS_ON_ERROR的作用就是告诉Swift:这个Objective-C方法的completion handler里的NSError参数,应该被转换成Swift的抛出机制。当闭包收到非nil的NSError时,Swift会自动抛出这个错误;同时你也可以在闭包内部主动抛出自定义错误,完全符合你的需求。
折中方案:如果暂时不能修改Objective-C代码(不推荐)
要是你临时没法调整Objective-C端,也可以手动把抛出闭包装成非抛出的,但这样会失去Swift抛出语法的便利性,只能手动处理错误:
// 假设你的抛出函数是这样的 func myThrowingHandler(strings: [String]?, error: Error?) throws { if let error = error { throw error } // 你的业务逻辑,可能抛出其他错误 } // 包装成非抛出闭包,手动处理错误 let wrappedHandler: ([String]?, Error?) -> Void = { strings, error in do { try myThrowingHandler(strings: strings, error: error) } catch { // 这里可以记录错误、上报,或者做其他处理,但没法继续抛出 print("处理时出错:\(error.localizedDescription)") } } // 传入getOptionalConfigurations getOptionalConfigurations(completion: wrappedHandler)
不过这个方案只是权宜之计,毕竟你没法真正抛出错误,只能在内部消化,所以还是优先用第一个修改Objective-C方法签名的方案。
内容的提问来源于stack exchange,提问作者Francesco Xu

