Search code examples
swiftgenericsenumsrawrepresentable

Storing Enum type in Swift


I am working on Enum serialization for my library (https://github.com/JiriTrecak/Warp) and I got little stuck on storing the enum type in the property (I need to know that type so I can serialize / deserialize it on demand).

I have a struct that contains description of all the properties that you can have, including their type, remote keys etc., and I'd like to store one more optional information if that is enum, which is the Enum type to be created when the key is found (say, Gender).

I've tried two approaches, both of which are not usable:

A) Declare the generic type in the container definition

public struct WRPProperty<T: RawRepresentable> {
    var enumType : T?

    public init(remote : String, enumType: T) {
        self.enumType = enumType
    }
}

This works, the problem with this approach is that I don't want every WRPProperty to have enum. By declaring it like this, it forces user to always add data type when creating the property, which is unwanted behavior. I can also create object that would be WRPEnumProperty, but that is not usable due to how the library handles those definitions and how user defines them.

B) Declare the generic type in the init method

public struct WRPProperty {
    var enumType : RawRepresentable

    public init<T: RawRepresentable>(remote : String, enumType: T) {
        self.enumType = enumType
    }
}

Which does not work, because RawRepresentable can only be used as generic constraint.

So my question is, how can I store the enum type, so I can then create any Enum of that type at any point? (Also, I am using Swift 2.2)


Solution

  • In your example (B) even if the compiler allowed it, there would be no way to guarantee that the init enumType was the same as the enumType property.

    The only solution that I can think of in this situation would be to ignore type safety and use Any

    public struct WRPProperty {
        var enumType:Any?
        public init<T:RawRepresentable>(remote : String, enumType: T) {
            self.enumType = enumType
        }
    }
    

    unless you can find some clever way of wrapping your values or employing a more sophisticated type erasure. This provides you with the dynamic ability you are looking for (although the best solution is probably to restructure your approach so that the enum Type can be set at instantiation if at all possible).