I am trying to dyanmically cast to a class in Swift. Is this possible? Here is the code I am trying to use:
let stringClass: AnyClass = NSString.self
let anyObje
I'm not sure exactly what you're trying to achieve, but here's a working version of your example:
func cast<T>(value: Any, to type: T) -> T? {
return castedValue as? T
}
let inputValue: Any = "this is a test"
let inputType = String.self()
let casted = cast(value: inputValue, to: inputType)
print(casted)
The x as! Y.Type
syntax only works when Y is explicitly stated.
So, the compiler wants x as! NSString
. The compiler crash is a bug, I suggest that you file a report.
And just think about it for a second, how would that even help you? stringClass
is of type AnyClass
, and you're force casting an AnyObject
which already conforms to AnyClass
. You should cast when you have a static type in mind, because casting doesn't really make any sense otherwise.
If you want to check, however, whether your object's class is a subclass of a particular type, you'd use:
x is Y.Type
I'm not seeing what the cast at this point is for. You can write:
let controllersDictionary: [String: String] = [
"valueOne" : "bar",
"valueTwo" : "foo"
]
let identifier = controllersDictionary[value]!
let viewController = storyboard.instantiateViewController(withIdentifier: identifier)
The cast does nothing for you in the code that you have shown. viewController
is typed as UIViewController, but it is the correct underlying view controller subclass thanks to polymorphism; whatever the class is in the storyboard, that's the class of this instance.
The only time you need to cast down is when you have to message an instance with a message belonging only to the subclass, and you have not shown any such need at this point in your code.
Its possible so long as you can provide "a hint" to the compiler about the type of... T
. So in the example below one must use : String?
.
func cast<T>(_ value: Any) -> T? {
return value as? T
}
let inputValue: Any = "this is a test"
let casted: String? = cast(inputValue)
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
Why Swift doesn't just allow us to let casted = cast<String>(inputValue)
I'll never know.
One annoying scenerio is when your func has no return value. Then its not always straightford to provide the necessary "hint". Lets look at this example...
func asyncCast<T>(_ value: Any, completion: (T?) -> Void) {
completion(value as? T)
}
The following client code DOES NOT COMPILE. It gives a "Generic parameter 'T' could not be inferred" error.
let inputValue: Any = "this is a test"
asyncCast(inputValue) { casted in
print(casted)
print(type(of: casted))
}
But you can solve this by providing a "hint" to compiler as follows:
asyncCast(inputValue) { (casted: String?) in
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
}
While there are/will be ways to make this kind of thing work, the Swifty solution (IMO) is to have your desired classes adhere to a protocol that defines the shared behavior you're trying to use, or simply use a super class they have in common
This allows the dynamism requried (in most cases at least) while still allowing the compile-time checks that prevent run time errors.
For your example,
protocol Stringable {
func toString() -> String
}
extension String: Stringable {
func toString() -> String {
return self
}
}
let thing = "foo"
let anything: Any = thing
let test: String? = (anything as? Stringable)?.toString()
Note that this requires "Any" rather than "AnyObject" since you need to cast to a protocol
Since you mentioned ViewControllers, I thought this might help:
static func createViewController<T: UIViewController>(storyboard: String, scene: String) -> T? {
return UIStoryboard(name: storyboard, bundle: nil).instantiateViewControllerWithIdentifier(scene) as? T
}