17
17

More than 3 years have passed since last update.

【Swift】Result型を使ってみた

Posted at

Swift5.0以降でResult型が正式採用されました🎉
この前Loaderを新規で書く機会があって、Result型使えるじゃん! と思って使ってみました。

Result型とは

  • success/failureの2パターンだけもつEnum
  • エラー処理をswitch文を使ってシンプルに書ける
  • 実際の定義は下記
public enum Result<Success, Failure: Error> {
    case success(Success)
    case failure(Failure)
}
  • ジェネリクス型なので、Success/Failureの型は開発者が指定してやる必要がある
  • Swift5以前だと、オリジナルでこの手のResult型っぽいEnumを自分で書いていたりライブラリ入れたりしていたと思うので、それはもはや要らない

使い方

たとえばLoaderのDelegateメソッドで、Result型を返す仕様にするとしたら、下記みたいに書きます。

DataLoaderDelegate
protocol DataLoaderDelegate: AnyObject {
    func dataLoader(didReceive result: Result<Data, DataLoaderError>)
}
DataLoaderError
enum DataLoaderError: Error {
    case timeout
    case jsonParseFailed
}

この例だと、successのときはData型を返し、failureのときはDataLoaderErrorというカスタムErrorクラスを返します。

ViewController側の受け取り方

さて渡されたResultクラスをどう受け取ればいいかというと、下記みたいな感じで書けます。

DataLoaderDelegate
// MARK: DataLoaderDelegate
extension ViewController: DataLoaderDelegate {
    func dataLoader(didReceive result: Result<Data, DataLoaderError>) {
        switch result {
        case .success(let data):
            self.data = data
        case .failure(let error):
            print("DataLoaderError:" + error.localizedDescription)
        }
    }
}

Enumの連想値(Associated Value)をパターンマッチで取り出すのがポイントですね。
この取り出し方、実は今まで知らなかったんですけど、めちゃくちゃ便利ですね。
型情報も失われないのも嬉しい。

使いどころ

Result型自体は失敗する可能性のある非同期処理だけでなく、
try〜catch構文で書いていたようなエラー処理の代替手段にもなります。

Swift 5 のResultに備える

↑の記事とかをチラッと読んだ感じだと、非同期処理はResult使うことでコードが読みやすくなる典型例みたいです。
Swiftチーム内でもResultをいつ使うべきか、明確なコンセンサスがないみたいですが、
通常のエラー処理でResultを使うのは非推奨なのは確かなようです。

そうなると現状使いどころってAPI叩くときの非同期処理ぐらいしかユースケースないよな、って思いました。

17
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
17