8

I want to check whether the generic class type is an Array:

func test<T>() -> Wrapper<T> {
  let isArray = T.self is Array<Any>
  ... 
}

But it warns

Cast from 'T.type' to unrelated type 'Array' always fails

How can I solve this problem?

added: I've uploaded my codes to Gist. https://gist.github.com/nallwhy/6dca541a2d1d468e0be03c97add384de

What I want to do is to parse json response according to it's an array of model or just one model.

1

3 Answers 3

4

As commentator @Holex says, you can use Any. Combine it with Mirror and you could, for example, do something like this:

func isItACollection(_ any: Any) -> [String : Any.Type]? {
    let m = Mirror(reflecting: any)
    switch m.displayStyle {
    case .some(.collection):
        print("Collection, \(m.children.count) elements \(m.subjectType)")
        var types: [String: Any.Type] = [:]
        for (_, t) in m.children {
            types["\(type(of: t))"] = type(of: t)
        }
        return types
    default: // Others are .Struct, .Class, .Enum
        print("Not a collection")
        return nil
    }
}

func test(_ a: Any) -> String {
    switch isItACollection(a) {
    case .some(let X):
        return "The argument is an array of \(X)"
    default:
        return "The argument is not an array"
    }
}

test([1, 2, 3]) // The argument is an array of ["Int": Swift.Int]
test([1, 2, "3"]) // The argument is an array of ["Int": Swift.Int, "String": Swift.String]
test(["1", "2", "3"]) // The argument is an array of ["String": Swift.String]
test(Set<String>()) // The argument is not an array
test([1: 2, 3: 4]) // The argument is not an array
test((1, 2, 3)) // The argument is not an array
test(3) // The argument is not an array
test("3") // The argument is not an array
test(NSObject()) // The argument is not an array
test(NSArray(array:[1, 2, 3])) // The argument is an array of ["_SwiftTypePreservingNSNumber": _SwiftTypePreservingNSNumber]
Sign up to request clarification or add additional context in comments.

Comments

3

Try out define an array marker protocol. Refer to this answer.

protocol AnyTypeOfArray {}
extension Array: AnyTypeOfArray {}
extension NSArray: AnyTypeOfArray {}

func isArray<T>(type: T.Type) -> Bool {
    return T.self is AnyTypeOfArray.Type
}

print(isArray(type: [String].self))   // true
print(isArray(type: String.self))     // false

Comments

-1

You are not passing any argument, so there is no type and a generic function does not make sense. Either remove the generic type:

func() {}

or, if you want to pass an argument:

let array = ["test", "test"]
func test<T>(argument: T) {
    let isArray = argument is Array<Any>
    print(isArray)
}

test(argument: array)

Prints: true

3 Comments

@mayTree you still have no argument, i.e. you are not passing a type. How should the type of T be found out? What do you expect the method to return as T?
why do you need generics for that? a simple Any could do the job as well – and who does return the true value? because it is defintely not your method.
@holex I just wanted to keep the example. Certainly generics are not needed. Sorry, Replaced "returns" with "prints".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.