SwiftUIとUIKitが共存するアプリにおける色指定の注意点 (sRGB vs Generic RBG)

# モチベーション

UIKitを併用していて、Color.gray と、 UIColor.gray で指定した部分で色が異なることに気づきました。
SwiftUIでは、色は、 `Color` UIKitでは、 `UIColor` と別の型である。

コンソールにprint文出力して確認してもやはり値が異なる。

| Gray | 値 |
|:-----------------|:------------------|
| Color | 0x600002ea6b20 |
| UIColor | 0x6000030b1170 |

そもそも何故、SwiftUIだけではなく、UIKitを併用しないといけなかった理由は後半に書きます。

# ColorのデフォルトはsRGB

Colorの宣言部分をみるとデフォルト引数が sRGBになっていることがわかる。

```swift
extension Color {

    public enum RGBColorSpace {

        case sRGB

        case sRGBLinear

        case displayP3

        ...
        
        public init(_ colorSpace: Color.RGBColorSpace = .sRGB, red: Double, green: Double, blue: Double, opacity: Double = 1)

    }
}
```

SwiftUIの色のデフォルトは sRGB指定である。そしてUIColorで指定できる、Generic RGBが選択肢にない。

# UIColorで使い方によってRGBの種類が異なるのか？

| 使用方法| デフォルト | 例 |
|:-----------------|:------------------|:------------------|
| コード | sRGB| label.backgroundColor = UIColor(red: 245/255.0, green: 84/255.0, blue: 45/255.0, alpha: 1.0) |
| Color Literal | sRGB | <img width="721" alt="スクリーンショット 2019-10-12 10.17.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45426/cdcae2c4-e40a-24c9-82bf-0326117f22c6.png"> |
| AssetCatalogのColorSet | sRGB |<img width="758" alt="スクリーンショット 2019-10-12 10.19.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45426/f448ac2a-2518-ea2d-faec-7ee03070c359.png"> |

すべて、sRGBがデフォルトであることがわかる。

Appleの公式を読むと
https://developer.apple.com/documentation/uikit/uicolor

```
For apps linked against the iOS 9 SDK and earlier, or running on iOS 9 and earlier, 
colors use one of two color spaces:

- Device-Dependent Gray

- Device-Dependent RGB
```

UIColor.gray は iOS9以前から存在したからこれを Generic RGBから sRGBに 色合いを変えることはできなくて取り残されていると考えられる。

# みんな大好き16進数色指定extension

今回のようにデフォルトの `gray` を使用せずに、 個々で色を指定すると思うが、 せっかくなので、 16進数指定できるものを用意した。 Apple 的には Dark Mode対応のため、AssetCatalog で色指定してほしいのかな？なので使いみちはないかもしれないが一応書いておく。

```swift
// MARK: - Helper

extension UIColor {
    convenience init(hex: Int, alpha: CGFloat = 1) {
        let components = (
            R: CGFloat((hex >> 16) & 0xff) / 255,
            G: CGFloat((hex >> 08) & 0xff) / 255,
            B: CGFloat((hex >> 00) & 0xff) / 255
        )
        self.init(red: components.R, green: components.G, blue: components.B, alpha: alpha)
    }
}

extension Color {
    init(hex: Int, alpha: Double = 1) {
        let components = (
            R: Double((hex >> 16) & 0xff) / 255,
            G: Double((hex >> 08) & 0xff) / 255,
            B: Double((hex >> 00) & 0xff) / 255
        )
        self.init(
            .sRGB,
            red: components.R,
            green: components.G,
            blue: components.B,
            opacity: alpha
        )
    }
}
```

使い方

```swift
Color(hex: 0xdddddd)

UIColor(hex: 0xdddddd)
```

ちょっと補足、
UIColorは32bitも使われる時代に作られたものなので、alphaの引数が Doubleではなく、 CGFloatのエイリアスで32bitか64bitかでFloatなのかDoubleなのかを切り替えているが、Colorからは全面的に64bitなので気持ちよくDoubleに振り切っている。（さすがAppleだ)

```swift
    /// The native type used to store the CGFloat, which is Float on
    /// 32-bit architectures and Double on 64-bit architectures.
    public typealias NativeType = Double
```


[iOS 11に別れを告げられた悲しき32bitアプリたち](https://www.itmedia.co.jp/pcuser/articles/1709/24/news007.html)

それとalphaを opacity という単語に変えている。

# 補足

そもそもなぜアプリ内で UIColorを使おうと思ったかというと
以下の図を見てもらうとわかるように、Listを引っ張った時に、背景が白色で表示されてしまうのを対応するため

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45426/995cd130-2edb-3d74-9645-675040210012.gif">

initの中で、UITableViewのbackgroundColorを指定するためである。これだけのために、UIKitを指定するのは正直イケていないので、Appleが指定できるIFを用意してくれることを望む(もしSwiftUIで指定する方法をご存じの方がいましたら教えて下さい)

```swift
    init() {
        UITableView.appearance().backgroundColor = UIColor(hex: 0xdddddd)
    }

    var body: some View {
       List(consoleLogs, id: \.self) { value in
             Text(value)
                  .lineLimit(Int.max)
                  .fixedSize(horizontal: false, vertical: true)  
             }
       }
    }
```

# まとめ
ほとんどのアプリではGeneric RGBを使わずにsRGBを使っていて、UIColor.gray みたいなデフォルトの色を使うことはないと思うので実害はないだろう。

# 参考
- [iOSアプリ開発時に注意したい色空間(Generic RGB vs sRGB)](https://grandbig.github.io/blog/2019/03/16/srgb/)
- [Colors in iOS: Ensuring consistency between designs, Interface Builder and UIColor](http://www.vsanthanam.com/writing/2017/7/6/colors-in-ios-ensuring-consistency-between-designs-interface-builder-and-uicolor)