ライトモード固定だけどNavigationBarだけダークモード対応する時の対応

NavigationBarだけダークモード固定にする対応をする際に、前例がなくOSなどの差異もあって結構ハマってしまいました。

失敗例

まず僕が失敗してしまった失敗例です。

特定の画面だけの対応なのでprivateなextensionを生やしてtraitCollectionDidChangeを呼ぶ方法です。

13.1のOSで試したら問題なく以下でイベントを受け取ることができ表示の差し替えを行うことができたのですが、13.4のOSで試したところイベントを受け取ることができませんでした😇

private extension UINavigationController {
    open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        NotificationCenter.default.post(name: .自作の通知を飛ばす, object: nil)
    }
}

extensionの中でのoverrideについて調べてみたところ以下のようなドキュメントを見つけました。

他にも調べてみるとUIViewControllerのサブクラスであればoverrideできるっぽいんですが基本的にextensionの中ではoverrideは呼ばない方が良いみたいです。

Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) Extensions can add new functionality to a type, but they cannot override existing functionality.

https://nabeatsu.hatenablog.com/entry/2019/01/30/120439

対応方法

NavigationBarを継承したクラスの中でtraitCollectionDidChangeを呼び出してそれを使うことで対応しました。

class DarkModeNavigationController: UINavigationController {
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        NotificationCenter.default.post(name: .自作の通知を飛ばす, object: nil)
    }
}

独自のNavigationクラスの中でイベント検知

NotificationCenterで変更箇所に伝播

画像の切り替え

参考文献

Extensions

Swiftのextension内でのmethodのoverrideについて