🎨

Viewが参照するUIColorにはセマンティクスな名前を付ける

2023/05/17に公開

「セマンティクス」とは、言葉の意味や文脈を考慮した意味の解釈のことです。

では、iOSアプリ開発において、UIColorにセマンティクスな名前を付けるということはどういうことでしょうか?

UIColorが持っている2つのメソッドを見てみましょう。

UIColor.placeholderText
UIColor.red

.placeholderTextは使う箇所が明確ですが、.redからはそのような情報を得ることはできません。

このように、変数名に意味を持たせることで可読性やメンテナンス性が向上します。

逆にプリミティブな名前を付けると、様々な問題が起きます。その例を見てみましょう。

色の誤用が発生する

UIColorのプリミティブな名前を使用すると、色を誤用する可能性があります。たとえば、UIColor.blueを使用して、アプリの背景色やボタンの色に適した青を選択することができますが、アプリのテキストやリンクに使用するにはあまりにも明るすぎる場合があります。セマンティクスな変数名を使用すると、アプリのコンテキストに応じて適切な色を選択しやすくなります。

view.backgroundColor = .background
button.tintColor = .primary
label.textColor = .bodyText

このように、セマンティクスな名前を使用することで、アプリのコンテキストに合わせた色を選択しやすくなり、コンポーネント間の色の誤用が少なくなります。

色の変更が難しくなる

セマンティクスな変数名を定義しないということは、同じメソッドから作った色を複数の場所で共有することになります。

view.backgroundColor = .black
...
label.textColor = .black

ここで、背景色を変えるためにblackの色を少し薄いグレーに変更するとlabelのtextColorまでもが変わってしまいます。

この場合は、それぞれ

view.background = .background
...
label.textColor = .bodyText

などの名前にするのが良いでしょう。

dynamicColorを表現できなくなる

UIColorには、dynamicColorという仕組みがありダークモードやビューの階層によって異なる色として振る舞うことができます。

例えば、dynamicカラーにプリミティブな名前を付けると実際に表示される色と異なる名前を付けることになってしまいます。

view.backgroundColor = .white // ダークモードなら黒
view.backgroundColor = .white // ライトモードなら白

正しい名前を付けるには

このように、プリミティブな名前を使うと、色の意図が不明確になり、誤用や変更の難しさ、dynamicColorの表現不可能性など、多くの問題が生じる可能性があります。したがって、UIColorに対してはセマンティクスな名前を付けることが重要です。

もし今プリミティブな名前を使っていても問題ありません。セマンティクスは裏側にプリミティブな値を内包しているからです。

例えばUIColor.redをテキストの破壊的な色に使っているとしましょう。

label.textColor = .red

まずは、この.redを入れる入れ物を用意します。

破壊的な変更を行うテキストの色なので、destructiveTextが良いでしょう。

何に使う色なのか、ユーザーに伝えたいのはなんなのかを考えると自然に名前が導き出せます。


extension UIColor {
    static let destructiveText = UIColor()
}

続いて、dynamicColorのイニシャライザを使って.redを中に入れます。

extension UIColor {
    static let destructiveText = UIColor { traitCollection in
        return .red
    }
}

これで、セマンティクスな名前をUIColorに付けることができました。

label.textColor = .destructiveText

ダークモードの時に少し赤色が眩しいなら、dynamicColorを使って次のように色が変更できます。

extension UIColor {
    static let destructiveText = UIColor { traitCollection in
        if traitCollection.userInterfaceStyle == .dark {
            return .darkRed
        } else {
            return .red
        }
    }
}

ここで.darkRedというプリミティブな値が現れましたが、セマンティクスな変数を定義したおかげでviewに直接使われることはありません。
このように、Viewから参照する色はセマンティクスを通して呼び出すことが望ましいことがわかりました。

Discussion