はじめに
Swift で独自の Error
を作成する際は localizedDescription
を使わずに LocalizedError
の errorDescription
を使いなさいというのはよく聞く話です。この記事はなぜ localizedDescription
はダメなのかという話です。
参考
前提
独自のエラーとして下記のように Hoge
を実装してみます。
enum Hoge: Error {
case hoge
var localizedDescription: String {
return "hoge"
}
}
// hogeじゃない
(Hoge.hoge as Error).localizedDescription
(Hoge.hoge as Error).localizedDescription
は下記のような値になります。
The operation couldn’t be completed. (Hoge error 0.)
下記のようにしてやると localizedDescription
はちゃんと hoge になります。
enum Hoge: Error {
case hoge
}
extension Hoge: LocalizedError {
var errorDescription: String? {
return "hoge"
}
}
// hoge
(Hoge.hoge as Error).localizedDescription
Hoge.localizedDescription
を変更してもダメなのは Error
のデフォルト実装があるからそれで上書きされるというのをどこかで見かけてそうなんだと思っていました。
ですが下記のような実装をしても別に上書きされないじゃないかという疑問を持ちました。
protocol Fuga {
var fuga: String { get }
}
extension Fuga {
var fuga: String {
return "fuga"
}
}
enum Piyo: Fuga {
case piyo
var fuga: String {
return "piyo"
}
}
// piyo
(Piyo.piyo as Fuga).fuga
なぜ上書きされるのか
ではなぜ localizedDescription
は上書きされるのかということなのですがおそらく私の認識が間違っていたのです
Error
の localizedDescription
はプロトコルで定義されているわけではなくおそらく extension
なんですね。
Xcode で cmd + control + J で localizedDescription
の定義にとぶと下記のようになっていました。
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
extension Error {
/// Retrieve the localized description for this error.
public var localizedDescription: String { get }
}
つまり Fuga
の例でいうとこんな感じです。
protocol Fuga {}
extension Fuga {
var fuga: String {
return "fuga"
}
}
enum Piyo: Fuga {
case piyo
var fuga: String {
return "piyo"
}
}
// fuga
(Piyo.piyo as Fuga).fuga
errorDescription
の定義にとぶと下記のようにプロトコルで定義されていました。おそらくlocalizedDescription
内で errorDescription
を呼ぶような実装になっているものと思われます。
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
public protocol LocalizedError : Error {
/// A localized message describing what error occurred.
var errorDescription: String? { get }
おわりに
今まではそういうものだと思って独自エラーを作る際は errorDescription
を使っていましたがこれでスッキリ使えるようになりました