How to check for Enum types in Swift?

11,618

Solution 1

enum Things {
    case Thing1
    case Thing2
}

let something:Any = Things.Thing1

something.dynamicType == Things.self // true

update based on discussion ..

protocol P {}
enum Things:P {
    case Thing1
    case Thing2
}
enum Things2:P{
    case Things21
}

let something:Any = Things.Thing1
something.dynamicType == Things.self // true
if let p = something as? P {
    print(true)
}

let somethingelse: Any = Things2.Things21
if let p = somethingelse as? P {
    print(true)
}

Solution 2

Since Mirror.displayStyle is an optional enumeration, preferably use conditional unwrapping and type checking in same statement.

You could extend Mirror.displayStyle by an .equals method to make it readily accessible in case you want to do this enum check frequently.

extension Mirror.DisplayStyle {
    func equals(displayCase: Mirror.DisplayStyle) -> Bool {
        return self == displayCase
    }
}

enum Things {
    case Thing1
    case Thing2
}

let something:Any = Things.Thing1
let mirror = Mirror(reflecting: something)

/* short form: using nil coalescing and ternary conditional operator */
mirror.displayStyle?.equals(.Enum) ?? false ? print("Reflected type is an Enum") : ()

/* another option: or using if-let */
if let _ = mirror.displayStyle?.equals(.Enum) {
   print("Reflected type is an Enum")
}

Note that you needn't explicitly create and store a Mirror instance for this check, but can do it all in one expression, for some instance something of type Any:

Mirror(reflecting: something).displayStyle?.equals(.Enum) ?? false ? print("Reflected type is an Enum") : ()

Finally, if you're just interesting in doing some simple action base on the DisplayStyle case of different Any instances, you could create a function that switches over the different cases of this enum. Below, the "simple action" just prints the case.

//... 

func foo(mirror: Mirror) {
    if let dispStyle = mirror.displayStyle {
        switch(dispStyle) {
        case .Class: print("Reflected type is a Class")
        case .Collection: print("Reflected type is a Collection")
        case .Dictionary: print("Reflected type is a Dictionary")
        case .Enum: print("Reflected type is an Enum")
        case .Optional:  print("Reflected type is an Optional")
        case .Set:  print("Reflected type is a Set")
        case .Struct:  print("Reflected type is a Struct")
        case .Tuple:  print("Reflected type is a Tuple")
        }
    }
}

let something: Any = Things.Thing1
foo(Mirror(reflecting: something))

See also Language Reference for Mirror.DisplayStyle.

Share:
11,618
mbonness
Author by

mbonness

Updated on July 26, 2022

Comments

  • mbonness
    mbonness almost 2 years

    I am writing a serializer that can serialize enums and other Swift types (strings, objects, etc.). So I need to check if an Any parameter passed into my serializer is an Enum or something else. It seems like the only way to do this in Swift is using reflection. Does the code below seem reasonable or is there a better way to check for Enum types?

    enum Things {
        case Thing1
        case Thing2
    }
    
    let something:Any = Things.Thing1
    let mirror = Mirror(reflecting: something)
    if (mirror.displayStyle == .Enum) {
        print("Reflected type is Enum") // works
    }
    
    • Cristik
      Cristik over 8 years
      Why would you need to check the type?
    • dfrib
      dfrib over 8 years
      If you want to know the "underlying type", the I believe mirror.displayStyle is a good option. @Cristik: One situation where one might want to know the "underlying type" is when e.g. an array of Any contains optional as well as non-optional entries; checking .displayStile == .Optional could be one approach to prepare for (possibly) casting the Any elements to native Swift types.
    • user3441734
      user3441734 over 8 years
      Enum is not a type in Swift (as struct is not a type, Optional is not a type ... ), Mirror.DisplayStyle is enum with case Enum defined.
    • Cristik
      Cristik over 8 years
      @dfri string comparison is not a good approach, I was merely curious about the context of the problem as the might be some better approaches that detecting type at runtime.
    • Cristik
      Cristik over 8 years
      @user3441734: if it's not a type, then what an Enum is?
    • user3441734
      user3441734 over 8 years
      @Cristik Mirror.DisplayStyle is type with case Enum defined. enum is keyword, like struct is. with help of enum keyword you can define your own type Things, as OP did.
    • dfrib
      dfrib over 8 years
      @Cristik I see no string comparison above. As user3441734 says, Mirror.DisplayStyle is an enum itself, so the comparison in question is checking if .DisplayStyle holds case .Enum.
    • user3441734
      user3441734 over 8 years
      @Cristik func is not type too. func foo()->Void represents a type. that is why let f = foo works as expected.
    • Cristik
      Cristik over 8 years
      @dfri mea culpa that, I assumed it's a string. In this case your code sample is a valid one. Still trying to understand the domain of the OP's problem, though :)
    • Cristik
      Cristik over 8 years
      @user3441734 I understand the difference between keywords and actual types ;) But why do you insist that Optional is not a type?
    • user3441734
      user3441734 over 8 years
      @Cristic Optional<T> is generic construct, like Array<T>. Array<Int> represents a type, Array<Double> represents different type, Optional<Int> and Optional<String> are two different types. EDIT!!! SORRY!!! Optional<Wrapped> is a type!! My mistake!!
    • user3441734
      user3441734 over 8 years
      @Cristik now i am a little bit disoriented if Optional is a type or not :-). What do you think about Optional ?
    • Cristik
      Cristik over 8 years
      @user3441734 Optional is a type, and it's a generic type
    • user3441734
      user3441734 over 8 years
      @Cristik ... yes, and Array<Element> is too. For a moment I was 'out of service' :-)
    • dfrib
      dfrib over 8 years
      Note that Optional is indeed a type, per se, but is more of a wrapper type w.r.t. it's type specifics: Optional is, specifically, an enumeration, which can be descriped (somewhat simplified) as enum Optional<T> with only two cases, .None and .Some(T).
  • Cristik
    Cristik over 8 years
    What if the argument is another enum?
  • user3441734
    user3441734 over 8 years
    @Cristik I updated my notes, you are right Optional<Wrapped> is a type!@Cristik in that case it is another Swift type. enum doesn't represent a type, as struct etc. Things is a type in this example, you can instantiate it.
  • mbonness
    mbonness over 8 years
    This is nice but I was looking for something a little bit more generic, since my program will be using a lot of different enums I do not want to test for each of them individually.
  • user3441734
    user3441734 over 8 years
    @mbonness the information that "type is an Enum" is useful for something else than debug log etc. ?? Maybe for you can works if your own Things and other user-defined types conforms to some well defined protocol. than you can try to cast all your instances to that common protocol.
  • ScottyBlades
    ScottyBlades almost 4 years
    Are you missing an argument for the equals function?
  • dfrib
    dfrib almost 4 years
    @ScottyBlades I wrote this over 4 years ago, so I'm not really sure what you are referring to; is seems I intentionally design the equals function with a single function parameter, and afaics, all usages of it provide exactly one argument to it. Is the example no longer compiling? (Possible as this was probably based on ~Swift 3). If you are actively working with Swift and can update/approve the answer, please feel free to submit an edit proposal! (I rarely use Swift myself nowadays).