Search code examples
iosswiftswift3

What exactly is type `(val: string)` in Swift when calling `type(of: xxx)`


I am running the follow function on a particular custom type:

    let mirror = Mirror(reflecting: self)
    print("self \(self)");

    for (propName, propValue) in mirror.children {
        print("propname \(propName) ... \(propValue)", type(of: propValue))
    }

And it is printing out

self UserAuthInput.userEmail(val: [email protected])
propname Optional("userEmail") ... (val: "[email protected]") (val: String)

I am having a hard time wrapping my head around as a Swift newb what exactly (val: string) type means. I know it came from a definition like this:

    public enum UserAuthInput {

        case userEmail(val: String)

        case userPhone(val: String)
    }

However my question is,

1) How can I parse the [email protected] out of the (val: string) type object propValue?

2) How can I check that this particular self is of enum type thus special handling is needed?

Thank you!


Solution

  • It's a one-element tuple. This is confirmed by using another mirror to reflect the child's value:

    let mirror = Mirror(reflecting: UserAuthInput.userEmail(val: "[email protected]"))
    for (propName, propValue) in mirror.children {
        print("propname \(propName!) ... \(propValue)", type(of: propValue))
        let subMirror = Mirror(reflecting: propValue)
        print(subMirror.displayStyle!) // tuple
    
        // this is one way you can get its value
        print(subMirror.children.first!.value) // [email protected]
    }
    

    Normally you can't create one-element tuples, so I'm quite surprised by this too. Since you can't use the type (val: String) in code, you can't get the associated value's value by simply casting. One way, which I've shown above, is to use another mirror.

    This is consistent with the case of 2 or more associated values, which also makes propValue be of a tuple type.

    public enum UserAuthInput {
    
        case userEmail(val: String, val2: String)
    
        case userPhone(val: String)
    }
    
    let mirror = Mirror(reflecting: UserAuthInput.userEmail(val: "[email protected]", val2: "hello"))
    for (_, propValue) in mirror.children {
        print(type(of: propValue) == (val: String, val2: String).self) // true
    }
    

    To check whether the mirror is reflecting an enum, check displayStyle:

    if mirror.displayStyle == .enum {
        // enum!
    }