ダークモード対応で今注意すべきこと

この記事は [potatotips #65](https://potatotips.connpass.com/event/145538/) で発表した内容を一部テキスト化したものです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ダークモード対応で注意すべきことの発表資料です。<br>Macをダークモードにして作業している方必見です<a href="https://t.co/oZsGhNqvg7">https://t.co/oZsGhNqvg7</a><a href="https://twitter.com/hashtag/potatotips?src=hash&amp;ref_src=twsrc%5Etfw">#potatotips</a></p>&mdash; たなたつ (@tanakasan2525) <a href="https://twitter.com/tanakasan2525/status/1178979164734414853?ref_src=twsrc%5Etfw">October 1, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

2019/10/10追記
Xcode 11.2 Beta版で確認したところ、こちらの問題は直っているようでした！
https://developer.apple.com/documentation/xcode_release_notes/xcode_11_2_beta_release_notes
> The host system’s appearance no longer affects which fallback color is archived for an adaptive asset catalog color. (55570108)

# TL;DR

iOS 12 以下をサポートしつつ、ダークモード対応するなら、Mac をライトモードにしたほうが良いかもしれません。
ダークモードの Mac で xib/Storyboard を編集すると Asset Catalog で作成した色の RGB がダークモードの色になり、iOS 12 以下でダークモードの色が表示されるケースがあります。

xib/Storyboard に Asset Catalog で作成した色を設定した後で、その色を編集しても色の変更が View に反映されない可能性があります。 (iOS 12 以下のみ)

# 動作確認環境

- macOS Mojave 10.14.6
- Xcode 11.0 (11A420a)

この内容は環境に依存している可能性が高いため、記載しておきます。
もし、Catalinaなら直ってるよ、などの知見がある方はコメントいただけると嬉しいです！

# iOS 12 以下でダークモードの色が表示されてしまう
iOS 13 で動作確認をしながらダークモード対応を進め、ある程度進んだ段階で iOS 12 の端末で確認をすると、何故か一部の色がダークモードで表示されていました :scream: 

色々検証していく中で以下の問題が分かりました。

- Mac をダークモードにしていると、xib/Storyboard に埋め込まれるカスタム色 [^1] の RGB がダークモードの色になる
    - iOS 13 では外観モードに合わせた正しい色が表示されるが、 iOS 12 以下では埋め込まれた色が表示されてしまうケースがある
- xib/Storyboard にカスタム色を設定した後、 Asset Catalog でその色を編集しても View 側の色が変わらない (iOS 12 以下のみ)

[^1]: この文章内では簡易化のため Asset Catalog で作成した色のことをカスタム色と記載します

## Mac をダークモードにしていると、xib/Storyboard に埋め込まれるカスタム色の RGB がダークモードの色になる

このような色を作成します。名前は `DynamicColor` とします。ライトモードの時は赤、ダークモードの時は青が表示されるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91631/0432a127-2175-5569-93ef-a11ef815bf12.png)

この色を Mac がライトモードの時に xib/Storyboard 内の View に設定すると以下のような色が埋め込まれます。

```xml
<resources>
    <namedColor name="DynamicColor">
        <color red="1" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
    </namedColor>
</resources>
```

一方、Mac がダークモードの時に設定すると以下のような色になります。

```xml
<resources>
    <namedColor name="DynamicColor">
        <color red="0.0" green="0.0" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
    </namedColor>
</resources>
```

本来関係ないはずの Mac 本体の外観設定が iOS のリソースに反映されてしまっています... :innocent: 
これだけでもチーム内でライト派/ダーク派が分かれている場合、Git の差分を見るのが辛くなります...


続いて、以下のような View を用意します。単に IBInspectable で背景色を設定できる View です。 (検証用なので無駄なコードです)

```swift
class View: UIView {
    @IBInspectable var ibBackgroundColor: UIColor = .white {
        didSet {
            backgroundColor = ibBackgroundColor
        }
    }
}
```

そして、Mac をダークモードにした状態で、以下のように色を指定します。

↓デフォルトで用意されている Background で DynamicColor を設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91631/409b1720-8b48-4f93-17b1-aec7b150e2be.png)

↓IBInspectable で増えた項目を利用して DynamicColor を設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91631/210f836c-247c-da7f-56fe-a50dd9cd1a3f.png)


すると、iOS 12 で以下の表示になります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91631/74e75cd2-620c-7aba-3e8f-4bcb20875ec5.png" width=300px>

なぜか、IBInspectable で設定した背景色が iOS 12 なのにダークモードになっています！！！ :disappointed_relieved:

ちなみにこれを iOS 13 で確認すると以下のように正しい表示になります...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91631/6eb43e5f-87b4-4397-407b-8864055a8fa6.png)
 
### 対策

全パターンを把握できていませんが、IBInspectable (User Defined Runtime Attributes) で 設定した色はこの現象が起きやすいです。

この問題を回避するためには現状は Mac をライトモードにして作業することをおすすめします。

## Asset Catalog で後からその色を編集しても View 側の色が変わらない  (iOS 12以下のみ)

既に xib/Storyboard の View に設定した色を Asset Catalog で編集しても iOS 12 以下で色が変わらない問題があります。

先程のライトモードの色を赤から緑に変更してみます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91631/c4adc97a-e445-0e4d-6257-29e768fe4a0d.png" width=300px>
↓
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91631/6042cba5-c8d9-97ab-3888-af74fa19178e.png" width=300px>

すると以下のようなの表示になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91631/2dc38b2c-2361-8716-4fa0-e9a6f5493140.png)

左が iOS 12 で 右が iOS 13 です。iOS 12 の色が変更前の色になっていますね... :disappointed_relieved:

### 対策

色を後から変更しても一部変わらない箇所があるため、 参照先の xib/Storyboard の色を再設定したほうが良いです。
どこか一箇所の色を一旦別の色にし、 また元の色に戻すとそのファイル内の色は全部正しい色に更新されました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91631/e33a7a59-346f-ce53-d0d2-40673cc7a255.png" width=300px>

## (おまけ) スプラッシュスクリーンの 画像が更新されない問題

スプラッシュスクリーンの画像を ダークモード対応のために差し替えても 画像が更新されず、古い画像が出てしまうケースがありました。

こちらは昔からある問題で、LaunchScreen の Storyboard に  xcassets の画像を設定していると起きるようです。

参考
Launch Screen Image not Updating!!!
https://forums.developer.apple.com/thread/68244

# まとめ

iOS 12 以下をサポートする場合、現状のダークモード対応にはかなり課題があります。
それでもユーザーが期待している機能であることは間違いないので、上記の問題などを気をつけつつ、iOS 12 以下の端末での動作検証をしっかりと行い、リリースするようにしましょう。

上記の問題は https://developer.apple.com/bug-reporting/ で報告済みなので、なる早で直ることを期待しています。

検証に利用したリポジトリはこちらに置いておきます。
https://github.com/tattn/WeirdDarkMode-iOS12