Reputation: 89
I know the title is confusing but I could not find a better way to condense this: I have a generic function that needs to check if the generic class it receives belongs to a generic type of class or to another type of class, without knowing the final parameter of the generic class. This is a sample of what I am trying to solve:
public class GenericClass<T: Codable>: SomeProtocol {
var data: T?
init(data: T) {
self.data = data
}
}
public class LessGenericClass: SomeProtocol {
var specific: String?
init(specific: String) {
self.specific = specific
}
}
public func foo<T: SomeProtocol>(caller: T) {
if (caller as? GenericClass) != nil { /* do something */ } // --->>> THIS IS THE CRITICAL PART
if (caller as? LessGenericClass) != nil { /* do something else */ }
}
The issue I have is that the compiler expects that in the function foo the GenericClass is resolved. In the code above the error would be: 'Generic parameter 'T' could not be inferred in cast to 'GenericClass''. For example, this would work:
public func foo<T: SomeProtocol>(caller: T, completion: @escaping(T.returnType?) -> () ) {
if (caller as? GenericClass<String>) != nil { /* do something */ } //
if (caller as? LessGenericClass) != nil { /* do something else */ }
}
But if I have to declare every single type I can pass to the foo function it would defy the purpose of using generics. Any help would be appreciated
Upvotes: 0
Views: 378
Reputation: 32775
Even if you'd be able to do this, check if the passed argument is part of a possibly infinite set of generic types, how would you check the generic argument?
If you don't care about the generic argument, and you want to only find out if the argument is a GenericClass
, you could do some stringly programing:
if "\(T.self)".hasPrefix("GenericClass<") { /* do your critical stuff */ }
Note that this is error prone, as if you rename the class you'll also have to keep the strings updated.
Upvotes: 0
Reputation: 285039
This kind of runtime check is very unswifty.
A swiftier way is to add doSomething
as a protocol requirement
protocol SomeProtocol {
func doSomething()
// other stuff
}
public func foo<T: SomeProtocol>(caller: T, completion: @escaping(T.returnType?) -> ()) {
caller.doSomething()
}
Upvotes: 1