Swift check type against a generic type
You cannot tell a function what the types of its generic placeholders are (unlike with a generic struct). It must infer them from the context e.g. its arguments.
One way to do what you want is to add another argument related to type T
. Rather than pass in a dummy value, you could use the metatype of the type you want:
func generic<T>(parameter: AnyObject, type: T.Type) -> Bool {
if parameter is T {
return true
} else {
return false
}
}
let o: AnyObject = "hello"
generic(o, String.self) // true
generic(o, NSString.self) // also true
generic(o, Int.self) // false
However, I would ask you, what is it you think you're achieving here? You've essentially done nothing more than implement is
as a function:
o is String // true
o is NSString // true
o is Int // false
The point of generics is to operate on arguments generically, but you aren't giving the function any argument of a specific type to actually do any work on (hence the inability to infer one).
Use Swift `is` to check type of generic type
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
}
}
Swift - checking type of a generic class
One of the solutions can be to use a protocol for your generic List
:
protocol AnyList {}
class List<T>: AnyList {
var value: T
var next: List<T>?
...
}
func isList<T>(_ object: T) -> Bool {
object is AnyList
}
let a = List<Int>(value: 2)
let b = "something which is not a list"
print(isList(a)) // true
print(isList(b)) // false
Check type of generic class without respecting generic type constraint
It is hard to express how complicated the world gets once you start allowing non-final subclasses. If you can possibly make these final classes or protocols, many little sharp edges will go away.
What you say you want and the code you're writing don't really line up (which is very common when dealing with subclasses). So it matters what you really want.
I would like to check if param has a class of type B as a generic constraint.
Sure. That's easy.
class B : SomeInterface {
func someFunc(param: C) {
if let typed = param as? A<B> {
print(typed)
} else {
print("NO")
}
}
}
This will work anytime we get an A<B>
. It will not work if we receive A<SubClassOfB>
, even if that's passed to SubclassOfB.someFunc()
. (See what I meant about it being subtle?)
From your code, you seem to actually want "if I'm passed A<Self>
" where "Self" means "exactly my class, not a superclass or subclass." The only way I've ever seen that done is with a protocol extension:
extension SomeInterface {
func someFunc(param: C) {
if let typed = param as? A<Self> {
print(typed)
} else {
print("NO")
}
}
}
This allows Self
to be replaced with "my class." But note that this means someFunc(A<MySubclass>)
won't work. A<Self>
is not the same thing as A<Subclass>
. Note that you can add a where
clause to the extension to limit its scope:
extension SomeInterface where Self: B { ... }
If you mean "T
is either Self
or some subclass of Self
", maybe it's possible, but in my experience it gets more and more tricky and fragile. You can't make generic types covariant on their parameters in Swift, so A<Subclass>
is not itself a subtype of A<Superclass>
(that's a much trickier problem than it sounds like, and you wouldn't always want it to be true). This is the kind of crazy corner case that goes away if you'll just mark B
as final. Then most of the rat's nest goes away.
Type checking with generics and raw types?
This doesn't work because Swift wants to know the type of the generic. If you just want to access a property without dealing with the generic, you can extract that to a protocol.
protocol SomethingThatHasFoo {
var foo: String { get }
}
class SomeViewController<T>: UIViewController, SomethingThatHasFoo {
let foo = "foo"
}
class AnotherViewController {
private weak var someVC: UIViewController?
func someFunc() {
if let vc = someVC as? SomethingThatHasFoo {
print(vc.foo)
}
}
}
Related Topics
Swift: Function with Default Parameter Before Non-Default Parameter
Add Placeholder to Uitextfield, How to Set the Placeholder Text Programmatically in Swift
What Language Is Swift Written In
Swift - Take Nil as Argument in Generic Function with Optional Argument
Swift, Avaudiorecorder: Error 317: Ca_Debug_String: Inpropertydata == Null
Swift: How to Animate the Rowheight of a Uitableview
How to Convert Nsset to [String] Array
iOS - Arkit Node Disappear After 100M
Code Migration from Swift 2.X to Swift 4
Nested Types Inside a Protocol
One-Way Platform Collisions in Sprite Kit
Catch Objective-C Exception in Swift
Swift: How to Disable User Interaction While Touch Action Is Being Carried Out