Andy
Andy

Reputation: 11008

Check if a view controller one of few possible types in Swift

Can one use an array of types to refactor the following condition?

vc is ViewController1 || vc is ViewController2 || vc is ViewController3...

Upvotes: 1

Views: 121

Answers (3)

Sulthan
Sulthan

Reputation: 130200

One possible way:

let types: [Any.Type] = [CGFloat.self, Double.self, Float.self]

let myVar = 10.0
let isFloat = types.contains { myVar.dynamicType == $0 }

print("Is float: \(isFloat)")

Unfortunately, Swift doesn't allow us to test myVar is $0 directly with dynamic types. Therefore this is not very useful if we want to check subclasses.

I would really recommend the solution with a custom protocol.

Upvotes: 1

boidkan
boidkan

Reputation: 4731

You could make an extension like this:

import Foundation

extension SequenceType where Generator.Element == Any.Type{
    func containsType(object:Any)->Bool{
        let mirror = Mirror(reflecting: object)
        let objectType = mirror.subjectType
        return self.contains{objectType == $0}
    }
}

And you call it like this:

if [ViewController1.self, ViewController2.self, ViewController3.self].containsType(vc){
    //statement is true
}else{
    //Statement is false
}

In the documentation here it says This type may differ from the subject's dynamic type when self is the superclassMirror() of another mirror. This is in regards to .subjectType.

Upvotes: 2

Travis Griggs
Travis Griggs

Reputation: 22290

YES, but you shouldn't.

You CAN create an array of types:

let types:[Any.Type] = [CGFloat.self, Double.self, Float.self]

You MUST specify the type of the array as [Any.Type]. It can't figure it out on it's own.

You can even get a type from a variable that matches those.

let double = 42.13
double.dynamicType --> Double.Type
types.contains(double.dynamicType) --> true

As @werediver suggests, probably the most swift idiomatic way to do such in swift is to define an empty protocol:

protocol ExaltedViewController { }

and then conform your various classes to it:

extension ViewController1:ExaltedViewController { }
extension ViewController2:ExaltedViewController { }
extension ViewController3:ExaltedViewController { }

Then you can just test with

if vc is ExaltedViewController { ... }

The advantage of doing this is that you don't have to have a centrally managed list. If your code were a framework, where you wanted other peoples view controllers to be added into that list, they could simply adopt the protocol, rather than having to hunt down where the special list was and edit it.

An alternate approach is to use a switch statement with stacked is tests. Consider the following:

func typeWitch(something:Any) { // type divining function
    switch something {
    case is CGFloat, is Float, is Double:
        print("it's got floating point superpowers")
    case is Int, is Int16, is Int32, is Int8, is Int64:
        print("it's a signed int")
    default:
        print("it's something else")
    }
}

typeWitch("boo")
typeWitch(13)
typeWitch(42.42)

And of course, you can put the two approaches together.

Upvotes: 2

Related Questions