[iOS13] ダークモード対応の作業内容と感想

# はじめに

こちらの記事を参考にさせていただいて、個人開発しているアプリをダークモード対応してみました。
[iOS 13からのダークモード対応のコツ](https://qiita.com/gonsee/items/c04b73787730c0e831df)

手探り状態の作業でしたのでベストプラクティスではないかも知れませんが、何かの参考になればと思います。

開発環境：
・Xcode 11 GM seed 2
・Swift 5.1

# 作業内容

元々のアプリの作りとして、いわゆる"1 Storyboard 1 ViewController"方式を取っていました。

- 一つのStoryboardファイルに一つのViewControllerだけを定義
- 画面遷移はsegueを使わずにコードで行う
- なるべくCustom Classを作成して外観や挙動を統一する

（参考リンク）
[StoryboardのBestPracticeについて考える(1) 〜Storyboardの分割〜](https://qiita.com/UJIPOID/items/06284fc1d9ec8c49f8a1)
[StoryboardのBestPracticeについて考える(2) 〜ビューの再利用〜](https://qiita.com/UJIPOID/items/d9d0ebf5f34d73fb15d1#_reference-b47456245396088b4215)

ダークモード対応にあたり、Custom Classたちのコードにダイナミックカラー（ダーク/ライトモードに応じて変化するUIColorの仕組み）を適用する戦略を取りました。
※今回対応したアプリはDeployment TargetがiOS 10.3なので、Asset CatalogのColor Setは使いませんでした（Color SetはiOS 11以降対応のため）。

例としては、こんな感じです。

```swift:TitleLabel.swift
import UIKit

@IBDesignable
class TitleLabel: UILabel {
    override func layoutSubviews() {
        super.layoutSubviews()
        configure()
    }
}

extension TitleLabel {
    private func configure() {
        font = UIFont.systemFont(ofSize: 19.0, weight: .bold)
        textColor = .themeLabel
    }
}
```

```swift:UIColorHelper.swift
import UIKit

extension UIColor {
    public class func dynamicColor(light: UIColor, dark: UIColor) -> UIColor {
        if #available(iOS 13, *) {
            return UIColor { (traitCollection) -> UIColor in
                if traitCollection.userInterfaceStyle == .dark {
                    return dark
                } else {
                    return light
                }
            }
        }
        return light
    }

// （中略）

    class var themeLabel: UIColor {
        return dynamicColor (
            light: .darkGray,
            dark: .lightGray
        )
    }
}
```

Custom Class: TitleLabelを設定し、Storyboardのライト/ダークモード切り替えを行うと、以下のような見え方になります。

＜ダークモード＞
![スクリーンショット 2019-09-21 10.54.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122917/1ad1ebfd-202b-e103-08d1-347dd606e910.png)
＜ライトモード＞
![スクリーンショット 2019-09-21 10.54.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122917/dacbce20-62cb-31ae-0d63-c6e42c1c5d39.png)

- Xcode下部の「Interface Style」にて、ライト/ダークモードを切り替えることで、Custom Classのコードで設定した色がStoryboardに反映され、いちいちアプリを実行しなくても色の確認ができます。
- 一方、ViewControllerに色を設定するロジックを書いてもStoryboardでのライト/ダークモード切り替えには反映してくれないです。※もし私の認識不足でしたらコメント等で教えてください。
- ちなみに、「Interface Style」にてライト/ダークモードの切り替えを行うとStoryboardファイルに差分が発生します。ちょっと煩わしいですね…

![スクリーンショット 2019-09-19 14.31.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122917/3e0fc7b5-b5e7-9235-5695-b8443f889710.png)

# 感想とまとめ

**今回の戦略について**

今回の戦略だと、使用する全種類のViewに対するCustom Classが必要となり、以前はわざわざCustom Classを作る必要がなかったものを今回追加で作成したので、少々面倒でした。
例えばUILabelでも、TitleLabel、BodyLabel、InfoLabelなど、コンテキストに合わせて数種類…

Deployment TargetをiOS 10.3から11.0に変更して（つまりiOS 10は切って）、Color Setを定義して、Storyboardで各画面の各ViewにColor Setを直接設定した方が楽だったかな、という印象です。

**実業務のダークモード対応について**

実業務で開発しているアプリは、Storyboardを使わずコードでUIを作っている画面が多いですし、Deployment TargetがiOS 9だったりします。
コードでUIを作っている画面では、ViewControllerのviewDidLoadで各Viewの色を設定しています。

これだと、Storyboardでライト/ダークモードのプレビューはできないし（都度実行が必要）、Color Setは使えないしで、実業務でのダークモード対応はかなり面倒くさい事になりそうだな、という印象です。