I wanted to know if there was a way to call an initializer by only having the class name in Swift.
class Shape {
let name: String
var numberOfSides: Int?
init(name: String) {
self.name = name
}
}
Pseudo code:
let shapeClass = stringToClass("Shape")
let shape: Shape = shapeClass(name: "Something")
More than just trying to call a class function, you are trying to call an initializer dynamically. To be able to call an initializer dynamically on a class that you get at runtime, the compile-time type of that class value must be a metatype of a class that has that initializer; but since initializers are not always inherited in Swift, that initializer must be declared required
.
Here we use NSClassFromString
to get a class from a string. (I am declaring the classes as @objc
with an explicit name, because otherwise Swift class names are mangled from the perspective of Objective-C and it's would be a pain to deal with.) However, it returns AnyClass
(i.e. AnyObject.Type
), which is a metatype whose values are any class. We want it to be restricted to classes that inherit from Shape
, so we can use Shape
's initializer, so we cast it to Shape.Type
(the metatype whose values are classes that descend from Shape
, inclusive).
I also demonstrate that it is polymorphic as it works with the name of a subclass by simply changing the name.
import Foundation
@objc(Shape)
class Shape {
let name: String
var type: String
required init(name: String) {
self.name = name
self.type = "Shape"
}
}
@objc(SubShape)
class SubShape : Shape {
required init(name: String) {
super.init(name: name)
self.type = "SubShape"
}
}
let shapeClass = NSClassFromString("SubShape") as Shape.Type
let shape: Shape = shapeClass(name: "Something")
println(shape.type) // prints "SubShape"