Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Swift `is` to check type of generic type

Tags:

generics

swift

Lets say that I have a variable of type Any, and I would like to know wether this is an array or not, here is what I would like to do:

if myVariable is Array { /* Do what I want */ }

But Swift requires to give the generic type of the array such as :

if myVariable is Array<Int> { }

But I don't want to check the generic type, I just want to know wether this is an array or not, I tried :

if myVariable is Array<Any> { }  

Hoping that it would match every type of array, but that doesn't work either... (it doesn't match arrays of all types, so if my variable is an Int array, this code doesn't get called for instance)

What should I do ?

Thank you.

Edit with example of an approach solution that doesn't seem to work:

struct Foo<T> {}

struct Bar {
    var property = Foo<String>()
}

var test = Bar()

let mirror = Mirror(reflecting: test)

// This code is trying to count the number of properties of type Foo
var inputCount = 0
for child in mirror.children {
    print(String(describing: type(of: child))) // Prints "(Optional<String>, Any)"
    if String(describing: type(of: child)) == "Foo" {
        inputCount += 1 // Never called
    }
}

print(inputCount) // "0"
like image 899
Pop Flamingo Avatar asked Jan 08 '17 15:01

Pop Flamingo


People also ask

Which of the following are generic types in Swift?

Swift 4s 'Arrays' and 'Dictionary' types belong to generic collections. With the help of arrays and dictionaries the arrays are defined to hold 'Int' values and 'String' values or any other types.

What is the use of generics in Swift?

Generics in Swift allows you to write generic and reusable code, avoiding duplication. A generic type or function creates constraints for the current scope, requiring input values to conform to these requirements.


2 Answers

Here's 2 things that might work for you.

Option 1:

Note that child is a tuple containing a String? with the name of the property ("property" in your example) and the item. So you need to look at child.1.

In this case, you should be checking:

if String(describing: type(of: child.1)).hasPrefix("Foo<")

Option 2:

If you create a protocol FooProtocol that is implemented by Foo<T>, you could check if child.1 is FooProtocol:

protocol FooProtocol { }

struct Foo<T>: FooProtocol {}

struct Bar {
    var property = Foo<String>()
}

var test = Bar()

let mirror = Mirror(reflecting: test)

// This code is trying to count the number of properties of type Foo
var inputCount = 0
for child in mirror.children {
    if child.1 is FooProtocol {
        inputCount += 1
    }
}
like image 132
vacawama Avatar answered Sep 29 '22 20:09

vacawama


This is how to test a generic type parameter for conformance:

let conforms = T.self is MyProtocol.Type

See this post: Swift: check if generic type conforms to protocol

like image 39
Leslie Godwin Avatar answered Sep 29 '22 21:09

Leslie Godwin