iOS
Swift

タイムアウト時のError(NSError)判定を短く書くのはどうでしょうか

結論

例えば次のようなExtensionどうよ、というのを思いついた。

extension Error {
    var isTimeOut: Bool {
        let nsError = self as NSError
        return (nsError.domain == NSURLErrorDomain && nsError.code == NSURLErrorTimedOut) ? true : false
    }
}

導入

FoundationのNSErrorでタイムアウトかどうかを判定する時、ErrorをNSErrorにキャストしてたりすると処理が冗長になったりする。

例えばこんな感じ

let nsError as error
if nsError.domain == NSURLErrorDomain && nsError.code == NSURLErrorTimedOut {
  // タイムアウト
}

このような2つの定数と比較するの短くしたいよねっていう思いつきの話です。

んで、APIKitを使っていると、SessionTaskErrorのenumからErrorを取り出さないといけなかったりする。

// APIKitのSessionTaskError

public enum SessionTaskError: Error {
    /// Error of `URLSession`.
    case connectionError(Error)

    /// Error while creating `URLReqeust` from `Request`.
    case requestError(Error)

    /// Error while creating `Request.Response` from `(Data, URLResponse)`.
    case responseError(Error)
}

ViewControllerでエラーに従ってハンドリングしたくなった場合はViewControllerでまずerrorを取り出して...とかやってるとコード読むの大変だなと。

if let error = error {
    if case .connectionError(let urlSessionError) = error, nsError.domain == NSURLErrorDomain && nsError.code == NSURLErrorTimedOut)
                 urlSessionError.isTimeOut {

なので、最初の結論に上げたようにExtensionでやったらどうなのよってのを思いついたわけです。

もちろん最初のコードは一行で書けるのでそこは好みや決めでいいとは思います。

extension Error {
    var isTimeOut: Bool {
        return (self as NSError).domain == NSURLErrorDomain && (self as NSError).code == NSURLErrorTimedOut
    }
}

最初、何で三項演算子使ってたかというと、条件判定の.domainと.codeが条件通りかどうかというのと、このメソッドがtrueかfalse返すのは結果がたまたま同じだから、その結果は別という考えがあるからです。理解されないかもしれないけど、条件は条件、結果は結果として表現したい。だからそのまま結果を返さなかったというわけです。

みなさんはどんな感じでしょうか?

追記

こうすれば簡単に比較できるんでextensionなんて作らないほうが良さそうですね...

if let error = self as? URLError, error.code == URLError.timedOut {
    return true
}