I have tried creating an instance of a class using a string in numerous ways with none of them working in Swift 3.
Below are pre-Swift 3 sol
If you project contains space you should replace space with '_'
Something like this
let namespace = (Bundle.main.infoDictionary!["CFBundleExecutable"] as! String).replacingOccurrences(of: " ", with: "_")
let cls = NSClassFromString("\(namespace).\(className)")! as! AnyClass
Apple provides a way to achieve this without having to use NSClassFromString
.
Bundle.main.classNamed("MyClassName")
https://developer.apple.com/documentation/foundation/bundle/1407299-classnamed
You can have a typed class from a string like:
let loadedClass = try! Bundle.main.class(ofType: MyClass.self)
using this simple extension:
extension Bundle {
func `class`<T: AnyObject>(ofType type: T.Type, named name: String? = nil) throws -> T.Type {
let name = name ?? String(reflecting: type.self)
guard name.components(separatedBy: ".").count > 1 else { throw ClassLoadError.moduleNotFound }
guard let loadedClass = Bundle.main.classNamed(name) else { throw ClassLoadError.classNotFound }
guard let castedClass = loadedClass as? T.Type else { throw ClassLoadError.invalidClassType(loaded: name, expected: String(describing: type)) }
return castedClass
}
}
extension Bundle {
enum ClassLoadError: Error {
case moduleNotFound
case classNotFound
case invalidClassType(loaded: String, expected: String)
}
}
Of course you can try
catch
the error
;)
You can try this:
func classFromString(_ className: String) -> AnyClass! {
/// get namespace
let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String
/// get 'anyClass' with classname and namespace
let cls: AnyClass = NSClassFromString("\(namespace).\(className)")!
// return AnyClass!
return cls
}
use the func like this:
class customClass: UITableView {}
let myclass = classFromString("customClass") as! UITableView.Type
let instance = myclass.init()