Search code examples
swiftenumsuikituicolor

How to use UIColor as RawValue of an enum type in Swift


I was trying to declare an enum type using UIColor as the raw value. Here is the code:

enum SGColor: UIColor {
    case red = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
    case green = #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)
    case purple = #colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1)
}

But I got two errors in the first line:

'SGColor' declares raw type 'UIColor', but does not conform to
RawRepresentable and conformance could not be synthesized

Do you want to add protocol stubs? Fix it

Raw type 'UIColor' is not expressible by any literal

If I took the first advice, Xcode will add typealias RawValue = <#type#> at the beginning inside of the parentheses. But I am not sure what to do with it. And if I were to address the second error, how do I change the raw type to a literal?


Solution

  • After some digging, I found a post by Ole Begemann that mentions how to make a customized color enumeration collection, which is SGColor in this question, conform to the RawRepresentable protocol.

    Basically, while Xcode is smart to suggest me to fix the problem by explicitly telling it the raw type (as seen in the first error in the question), it is still not intelligent enough to figure out how to do that for color literals, or UIColor.

    Ole Begemann mentioned a manual conformance will fix this. And he gave a detailed explanation as of how to do it.

    While he used UIColor color objects (such as UIColor.red), I tried and tested the feasibility of using color literals, since in general, they are more visually direct and more customizable.

    enum SGColor {
        case red
        case green
        case purple
    }
    extension SGColor: RawRepresentable {
        typealias RawValue = UIColor
    
        init?(rawValue: RawValue) {
            switch rawValue {
            case #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1): self = .red
            case #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1): self = .green
            case #colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1): self = .purple
            default: return nil
            }
        }
    
    var rawValue: RawValue {
            switch self {
            case .red: return #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
            case .green: return #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)
            case .purple: return #colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1)
            }
        }
    }