Swift中如何检测Error是否遵循自定义协议?
问题:Swift中无法检测Error实例是否遵循自定义协议
我定义了一个继承自Error的自定义协议LoggableError,并给系统类URLError做了扩展来遵循该协议,但在接收Error实例时,无法通过as?或is检查判断它是否实现了LoggableError协议。示例代码如下:
import Foundation protocol LoggableError: Error { var message: String { get } } extension URLError: LoggableError { var message: String { switch code { case .notConnectedToInternet: return "no internet" default: return "" } } } func log(error: Error) { guard let error = error as? LoggableError else { // 该类型转换失败 return } print(error.message) } let error = URLError(.notConnectedToInternet) log(error: error)
注意:如果在log(error:)方法中将实例转换为URLError则可以成功检测与转换,这是为什么?
原因解析
这是因为Error是一个**@objc协议**(底层基于Objective-C错误机制实现),而你定义的LoggableError是纯Swift协议,未标记@objc。当协议继承自@objc协议时,Swift的类型检查机制在处理动态装箱的Error实例时,无法正确识别纯Swift协议的一致性:
- 当
URLError实例以Error类型传递时,会被装箱为Objective-C兼容的错误对象,此时Swift无法直接从该对象上检测到它遵循了纯Swift的LoggableError协议。 - 直接转换为
URLError可以成功,因为这是对具体类的类型检查,Swift能直接识别实例的实际类型,无需处理协议一致性的跨层兼容问题。
解决方法
给LoggableError协议加上@objc标记,使其成为Objective-C兼容协议,即可正常完成类型转换:
import Foundation @objc protocol LoggableError: Error { var message: String { get } } extension URLError: LoggableError { var message: String { switch code { case .notConnectedToInternet: return "no internet" default: return "" } } } func log(error: Error) { guard let error = error as? LoggableError else { return } print(error.message) // 现在会输出"no internet" } let error = URLError(.notConnectedToInternet) log(error: error)
如果协议需要包含纯Swift特性(比如关联类型)无法标记@objc,可以改用类型擦除,或者在接收Error时先尝试转换为已知的具体错误类型,再检查协议一致性。
内容的提问来源于stack exchange,提问作者JorisT
相关产品推荐
相关产品推荐

