Swift & Objective-C

Swiftでカスタムエラーメッセージを定義する:LocalizedError完全ガイド(サンプル付き)

Swiftでアプリを作っていると、do-catchでエラーを捕捉したのに、画面に表示するメッセージがいまひとつだった経験はありませんか。

読了 5 分
Swiftでカスタムエラーメッセージを定義する:LocalizedError完全ガイド(サンプル付き)のカバー画像

Swiftでアプリを作っていると、do-catchでエラーを捕捉したのに、画面に表示するメッセージがいまひとつだった経験はありませんか。

error.localizedDescriptionをそのまま使うと、“The operation couldn’t be completed…“のような正体不明の文言がユーザーにそのまま表示されがちです。

結論からお伝えします。

Swiftでユーザーに表示するカスタムエラーメッセージを定義するには、ErrorではなくLocalizedErrorプロトコルを採用し、errorDescriptionプロパティを実装します。

今日はこの方法をサンプルとともに順を追って見ていきます。


なぜErrorだけでは不十分なのでしょうか?

多くの方は、次のようにエラーを定義するでしょう。

enum LoginError: Error {
    case invalidPassword
    case userNotFound
}

この状態でerror.localizedDescriptionを出力すると、期待した「パスワードが間違っています」ではなく、システムが生成した味気ないデフォルト文言が表示されます。

Errorプロトコル自体には、人が読めるメッセージを定義する場所がないためです。

そこで登場するのがLocalizedErrorです。


Swiftのカスタムエラーメッセージはどう定義する?

方法は簡単です。LocalizedErrorを採用し、errorDescriptionを実装します。

以下は、ログインエラーにユーザー向けメッセージを追加した例です。

extension LoginError: LocalizedError {
    var errorDescription: String? {
        switch self {
        case .invalidPassword:
            return "パスワードが正しくありません."
        case .userNotFound:
            return "存在しないユーザーです."
        }
    }
}

これでerror.localizedDescriptionを呼び出すと、定義した文言がそのまま表示されます。

ポイントは、errorDescriptionの戻り値の型がString?、つまりオプショナルであることです。

ここでnilを返すと、システムのデフォルトメッセージに戻ってしまいます。そのため、すべてのケースに値を設定することが重要です。

ケースごとに文字列を設定することがポイントです。
ケースごとに文字列を設定することがポイントです。

errorDescription以外にもありますか?(failureReason・recoverySuggestion)

はい。LocalizedErrorには、任意で実装できるプロパティがほかにもあります。

役割を表にまとめると、次のようになります。

プロパティ 役割 例文
errorDescription 何が問題だったか 「ログインに失敗しました。」
failureReason なぜ発生したか 「パスワードを5回間違えました。」
recoverySuggestion どう解決するか 「しばらくしてからもう一度お試しください。」

特にrecoverySuggestionは、ユーザーに次の行動を案内するときに便利です。

実際、SwiftUIのAlertやAppKit環境では、これらの値を自動的に読み取って画面に配置してくれることもあります。

ユーザー向けエラーなら、少なくともerrorDescriptionrecoverySuggestionの2つは用意するようにしています。


開発用ログとユーザーメッセージを混同しない

最後に1つだけ付け加えます。

デバッグログに記録したい開発者向けの説明はCustomStringConvertible(つまりdescription)に、

ユーザーに表示する翻訳済みメッセージはLocalizedErrorに分けることをおすすめします。

目的が異なるからです。一方は自分のため、もう一方はユーザーのためのものです。

このように役割を分けておけば、後から多言語対応するときもNSLocalizedStringを追加しやすくなります。


今日の内容を一言でまとめると、「ユーザーに表示するエラーなら、まずLocalizedErrorerrorDescriptionを埋めよう」です。

小さな習慣ひとつでユーザー体験は大きく変わるので、次のプロジェクトでぜひ試してみてください。応援しています!🙌


参考資料

あわせて読みたい