从 classname 创建一个 swift2 class

Create a swift2 class from classname

我是 Swift 的新人。

在 objective C 中,我推送了从其 class 名称创建的自定义 UIViewController:

NSString *classString = "customViewController";
UIViewController *vc = [[NSClassFromString(classString) alloc] init];
[self pushViewController:vc animated:YES];

我无法在 swift 中构建 class,这不起作用:

let myClass = NSClassFromString("customViewController") as! UIViewController.Type
let vc = myClass.init()
self.presentViewController(vc, animated: true, completion: nil)

Error : fatal error: unexpectedly found nil while unwrapping an Optional value

NSClassFromString 使用完全限定的 class 名称。

class CustomViewController: UIViewController { }

let className = NSStringFromClass(CustomViewController.self)
// let className = "MyAppName.CustomViewController" // Equivalent
let aClass = NSClassFromString(className) as! UIViewController.Type
let viewController = aClass.init()

或者,您可以使用 @objc 属性覆盖完全限定的 class 名称:

@objc(CustomViewController)
class CustomViewController: UIViewController { }

let className = NSStringFromClass(CustomViewController.self)
// let className = "CustomViewController" // Equivalent
let aClass = NSClassFromString(className) as! UIViewController.Type
let viewController = aClass.init()

无论哪种方式,NSStringFromClass 将始终 return NSClassFromString 方法的有效 class 名称。

失败的原因是您引用的视图控制器 class 名称 (customViewController) 未完全符合 模块名称 。这可以在自定义 class 名称下方的 Interface Builder 中找到:

您应该更改 class 名称字符串以表示视图控制器的完全限定名称,例如:

let myClass = NSClassFromString("MyProject.customViewController") as! UIViewController.Type

我创建了一个非常简单的扩展来更快地执行此操作 https://github.com/damienromito/NSObject-FromClassName

extension NSObject {
    class func fromClassName(className : String) -> NSObject {
        let className = NSBundle.mainBundle().infoDictionary!["CFBundleName"] as! String + "." + className
        let aClass = NSClassFromString(className) as! UIViewController.Type
        return aClass.init()
    }
}

在我的例子中,我这样做是为了加载我想要的ViewController:

override func viewDidLoad() {
    super.viewDidLoad()
    let controllers = ["SettingsViewController", "ProfileViewController", "PlayerViewController"]
    self.presentController(controllers.firstObject as! String)

}

func presentController(controllerName : String){
    let nav = UINavigationController(rootViewController: NSObject.fromClassName(controllerName) as! UIViewController )
    nav.navigationBar.translucent = false
    self.navigationController?.presentViewController(nav, animated: true, completion: nil)
}