1
2

【Swift】CustomStringConvertibleについて調べてみた

Last updated at Posted at 2024-08-03

アップルさんのサンプルコードを調べているときに、CustomStringConvertibleというProtocolを使っていました。
見たことあるけどどういうものだったかな? と疑問に感じたので、調べてみました。

CustomStringConvertibleとは

Types that conform to the CustomStringConvertible protocol can provide their own representation to be used when converting an instance to a string. The String(describing:)initializer is the preferred way to convert an instance of any type to a string. If the passed instance conforms to CustomStringConvertible, the String(describing:) initializer and the print(_:) function use the instance’s custom description property.
Accessing a type’s description property directly or using CustomStringConvertible as a generic constraint is discouraged.

CustomStringConvertibleプロトコルに準拠したタイプは、インスタンスを文字列に変換するときに使用する独自の表現を提供できます。String(describing:)イニシャライザは、任意の型のインスタンスを文字列に変換する好ましい方法です。渡されたインスタンスがCustomStringConvertibleに準拠している場合、String(describing:)初期化子とprint(_:)関数は、インスタンスのカスタム記述プロパティを使用します。
型の説明プロパティに直接アクセスしたり、CustomStringConvertibleを一般的な制約として使用したりすることはお勧めできません。

公式ドキュメントより抜粋。日本語訳はmacOSの翻訳機能にお願いしました)

サンプルコード

Point構造体をprint関数で文字列にした場合にどうなるかみてみましょう。

struct Point {
    let x: Int, y: Int
}

let p = Point(x: 21, y: 30)
print(p) // "Point(x: 21, y: 30)"

Point(x: 21, y: 30) という文字列に変換されました。
これでも内容はわかりますが、Pointはいらないなということがあるかと思います。

そんな場合に、CustomStringConvertibleの登場です。

struct Point: CustomStringConvertible {
    let x: Int, y: Int

    var description: String {
        return "(\(x), \(y))"
    }
}

let p = Point(x: 21, y: 30)
let s = String(describing: p)
print(s) // (21, 30)

Pointが消えて、見事に (21, 30) という文字列に変換できました。
名前のとおり、カスタムできるというわけですね。

注意点

下記のコードのように直接descriptionプロパティにアクセスすることはできるし、取得する値も String(describing:) を使った場合と同じになります。
しかし、上記の公式ドキュメントによるとお勧めできないそうです。理由が書かれていませんが、将来的に仕様が変わる(プロパティにアクセスできないようになる等)可能性もあるので、素直に String(describing:) を使いましょう。

print(p.description) // (21, 30)

使用例

アップルさんのサンプルコード Backyard Birds から、CustomStringConvertibleの使用例を見てみましょう。
サブスクリプションの種類を表すenumのPassStatusを宣言して、extensionでCustomStringConvertibleに準拠しています。そして、descriptionでは、caseごとの説明を返すようにしています。

enum PassStatus: Comparable, Hashable {
    case notSubscribed
    case individual
    case family
    case premium
}

extension PassStatus: CustomStringConvertible {
    var description: String {
        switch self {
        case .notSubscribed: String(localized: "Not Subscribed")
        case .individual: String(localized: "Individual")
        case .family: String(localized: "Family")
        case .premium: String(localized: "Premium")
        }
    }
}

次に、PassStatusのdescriptionを使用しているところを見てみます。

    @ViewBuilder
    private var manageSubscriptionLabel: some View {
        Label {
            Text("Your Backyard Birds Pass: \(String(describing: passStatus))",
                 comment: "The variable is the type of Backyard Birds Pass (such as Premium, Family, and so on.)")
        } icon: {
            Image(systemName: "wallet.pass")
        }
        #if os(macOS)
        .labelStyle(.titleOnly)
        #endif
    }

LabelのTextで使用しています。
Your Backyard Birds Pass: の後ろの \(String(describing: passStatus)) で PassStatus に定義した description を取得して表示しています。

それでは、実際の画面を見てみましょう。

PassStatusのdescription画面

お使いのBackyard Birds パス: の後ろに 個人 と表示されています(あらかじめサブスクリプション画面で Individual を選択してあります)。

CustomStringConvertibledescriptioncase .individual: String(localized: "Individual") が選択されて "Individual" が返ってきていることがわかります。

余談ですが、 "Individual"個人 になっているのはLocalizableが設定されているからです。

スクリーンショット 2024-08-03 10.50.58.png

終わりに

自分でコードを書くときには、下記のようにnameを定義していました。

enum PassStatus: Comparable, Hashable {
    case notSubscribed
    case individual
    case family
    case premium
    
    var name: String {
        switch self {
        case .notSubscribed: String(localized: "Not Subscribed")
        case .individual: String(localized: "Individual")
        case .family: String(localized: "Family")
        case .premium: String(localized: "Premium")
        }
    }
}

標準のprotocolがあるならそちらを使ったほうがわかりやすくていいなと思うので、これからはCustomStringConvertibleを活用します。

それでは、Have a good Swift life! Have a good CustomStringConvertible iife!

1
2
1

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
1
2