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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 04:22:35