Reputation: 37043
I have an array of AnyObject
, and I would like to cast it (or one of its objects) to a generic type T
which may or may not be an array.
My first attempt:
class MyClass<T> {
func someMethod() -> T? {
let anyObjectArray: [AnyObject] = // ... array obtained from Objective-C framework
if let objectsAsCollection = anyObjectArray as? T { // Cast always fails
return objectsAsCollection
} else if let firstObject = anyObjectArray.first as? T {
return firstObject
} else {
return nil
}
}
}
The first if let
cast fails when T
is an Array
(e.g. T.self == Array<SomeObject>.self
).
I would try something like this, but it involves introducing another generic parameter somehow, so isn’t valid as written:
extension MyClass where T == Array<U> {
fun someMethod() -> T? {
let anyObjectArray: [AnyObject] = // ... array obtained from Objective-C framework
if let objectsAsCollection = anyObjectArray.flatMap({ $0 as? U }) {
return objectsAsCollection
} else if let firstObject = anyObjectArray.first as? T {
return firstObject
} else {
return nil
}
}
}
The reason for wanting to do this is that I am using an Objective-C framework (RestKit) to get results from a REST API. I am building a layer on top in Swift which passes these results back as a specific type depending on the request that was made, so I have a Result
type that looks something like this:
enum Result<T>: {
case Success(T)
case Failure(Error)
}
Sometimes T
is a single object, sometimes it is an arrays of objects, but the Objective-C framework always returns results as an array.
Upvotes: 1
Views: 1052
Reputation: 130092
The following syntax will work:
class MyClass<T> {
func someMethod() -> T? {
// let's not convert to [AnyObject] here, keep it as NSArray
let anyObjectArray: NSArray = ...
// For some reason conversion from [AnyObject] to [T] fails...
// However, conversion from NSArray is special
if let objectsAsCollection = anyObjectArray as? T {
return objectsAsCollection
} else if let firstObject = (anyObjectArray as [AnyObject]).first as? T {
return firstObject
} else {
return nil
}
}
}
However, it is just a workaround for a probable bug. We can boil down the problem to the following:
class GenericClass<T> {
func someMethod() {
let anyObjectArray: [AnyObject] = ["test1", "test2", "test3"]
print(T) //Array<String>
print(T.self == Array<String>.self) //true
print(anyObjectArray is [String]) //true
print(anyObjectArray is T) //false - BUG
}
}
let instance = GenericClass<[String]>()
instance.someMethod()
(reported: SR-1054)
which looks like a clear bug to me. It actually looks like another instance of the bug discussed in Type of optionals cannot be inferred correctly in swift 2.2
Upvotes: 3