Swift:检查基础(NS)错误与自定义协议的一致性

Jor*_*Dor 4 protocols ios swift

使用案例:

为了能够记录错误,我们使它们符合特定的协议。这似乎适用于自定义错误,但是,检查或转换 Foundation 错误(例如 URLError)到此协议似乎失败了。

我不知道这里有什么不同。

在此示例中:我们有一个视图模型执行可能导致错误的操作。我们想用我们的记录器记录这个错误。

例子:


// Protocol that makes an error loggable

protocol LoggableError: Error {
    var message: String { get }
}

// Our custom error:

enum CustomError: Error {
    case someError
}

extension CustomError: LoggableError {
    var message: String {
        "Some error occurred"
    }
}

// URL error conforming to our LoggableError:

extension URLError: LoggableError {
    var message: String {
        "Some network error occurred"
    }
}

// The logger

protocol LoggerProtocol {
    func handle(error: some Error)
}

class Logger: LoggerProtocol {
    func handle(error: some Error) {
        guard let error = error as? LoggableError else { fatalError("Cast failed") }
        print(error.message)
    }
}

// The view model

class ViewModel {
    private let logger: LoggerProtocol

    init(logger: LoggerProtocol) {
        self.logger = logger
    }

    func doSomething() {
        do {
            try doSomethingDangerous()
        } catch {
            logger.handle(error: error)
        }
    }

    private func doSomethingDangerous() throws {
        throw CustomError.someError // this works
        // throw URLError(.notConnectedToInternet) // this triggers the fatalError
    }
}

// Trigger

let viewModel = ViewModel(logger: Logger())
viewModel.doSomething()
Run Code Online (Sandbox Code Playgroud)

谁能告诉我我做错了什么或者为什么这不起作用?Swift 开发已经 7 年了,我似乎仍然不明白协议:D

Rob*_*ier 5

首先,我认为这是 Foundation 中的一个错误,并建议打开有关它的反馈。但是您遇到的问题是由于 Darwin 上处理 NSError 的棘手方式造成的(这就是为什么您在 Linux 上看不到这个问题)。

许多 Foundation 错误实际上只是 NSError 的包装。尽管它们有自己的 Swift 类型,但它们无法在存在主义的往返中生存:

print(type(of: CustomError.someError))              // CustomError
print(type(of: CustomError.someError as any Error)) // CustomError

print(type(of: URLError(.notConnectedToInternet)))              // URLError
print(type(of: URLError(.notConnectedToInternet) as any Error)) // **NSError**
Run Code Online (Sandbox Code Playgroud)

(请注意,这与枚举与结构无关。如果将 CustomError 更改为结构,它仍然可以正常工作。问题是您看不到 NSError。)

走过来的时候也会出现类似的问题some。ObjC 和 Swift 类型最终不匹配。基金会错误有神奇的桥梁,使它们更加“敏捷”。但这是一个相当有漏洞的抽象,并且这是一个错误。

如果可能,您应该使 NSError 符合 LoggableError。这将解决这个问题。