I'm confused about dynamic type checking in Swift.
Specifically, I have a weirdo case where I want to, essentially, write (or find) a function:
func isInstanceOf(obj: Any, type: Any.Type) -> Bool
In Objective-C, this is isKindOfClass
, but that won't work because Any.Type
includes Swift structs, which are not classes (much less NSObject
subclasses).
I can't use Swift is
here, because that requires a hardcoded type.
I can't use obj.dynamicType == type
because that would ignore subclasses.
The Swift book seems to suggest that this information is lost, and not available for structs at all:
Classes have additional capabilities that structures do not:
...
- Type casting enables you to check and interpret the type of a class instance at runtime.
(On the Type Casting chapter, it says "Type casting in Swift is implemented with the is and as operators", so it seems to be a broader definition of "type casting" than in other languages.)
However, it can't be true that is
/as
don't work with structures, since you can put Strings and Ints into an [Any]
, and pull them out later, and use is String
or is Int
to figure out what they were. The Type Casting chapter of the Swift Book does exactly this!
Is there something that's as powerful as isKindOfClass
but for any Swift instances? This information still must exist at runtime, right?
Checking TypeUse the type check operator ( is ) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it's not.
A type annotation explicitly specifies the type of a variable or expression. Type annotations begin with a colon ( : ) and end with a type, as the following examples show: let someTuple: (Double, Double) = (3.14159, 2.71828)
Structs cannot have inheritance, so have only one type. If you point two variables at the same struct, they have their own independent copy of the data.
To get type of a variable in Swift, call type(of:) function, and pass the variable as argument for of: parameter.
Actually you can use is
operator.
Use the type check operator (is) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it is not.
Since struct
can't be subclassed, is
is guaranteed to be consistent when applied to instance of struct because it will check on it static type, and for classes it will query the dynamic type in runtime.
func `is`<T>(instance: Any, of kind: T.Type) -> Bool{
return instance is T;
}
This work for both, struct
and class
.
As already stated, is/as should work fine with structs. Other corner cases can usually be done with generic functions, something like:
let thing: Any = "hi" as Any
func item<T: Any>(_ item: Any, isType: T.Type) -> Bool {
return (item as? T) != nil
}
print(item(thing, isType: String.self)) // prints "true"
No idea if this fits your specific use case.
More generally, keep in mind that Swift (currently) requires knowing the type of everything at compile time. If you can't define the specific type that will be passed into a function or set as a variable, neither will the compiler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With