Swift语言NSClassFromString

如何在Swift语言中实现反思 ?

我怎样才能实例化一个类

[[NSClassFromString(@"Foo") alloc] init]; 

这里更简单的解决scheme: https : //stackoverflow.com/a/32265287/308315

请注意,Swift类现在是命名空间,所以而不是“MyViewController”它将是“AppName.MyViewController”


自XCode6-beta 6/7以来已弃用

使用XCode6-beta 3开发的解决scheme

感谢Edwin Vermeer的回答,我能够通过这样做来将Swift类实例化成一个Obj-C类:

 // swift file // extend the NSObject class extension NSObject { // create a static method to get a swift class for a string name class func swiftClassFromString(className: String) -> AnyClass! { // get the project name if var appName: String? = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as String? { // generate the full name of your class (take a look into your "YourProject-swift.h" file) let classStringName = "_TtC\(appName!.utf16count)\(appName)\(countElements(className))\(className)" // return the class! return NSClassFromString(classStringName) } return nil; } } // obj-c file #import "YourProject-Swift.h" - (void)aMethod { Class class = NSClassFromString(key); if (!class) class = [NSObject swiftClassFromString:(key)]; // do something with the class } 

编辑

你也可以用纯的obj-c来做:

 - (Class)swiftClassFromString:(NSString *)className { NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; NSString *classStringName = [NSString stringWithFormat:@"_TtC%d%@%d%@", appName.length, appName, className.length, className]; return NSClassFromString(classStringName); } 

我希望这会帮助别人!

你必须把@objc(SwiftClassName)放在你的swift类的上面。
喜欢:

 @objc(SubClass) class SubClass: SuperClass {...} 

这是我通过类名初始化UIViewController的方式

 var className = "YourAppName.TestViewController" let aClass = NSClassFromString(className) as! UIViewController.Type let viewController = aClass() 

更多信息在这里

在iOS 9中

 var className = "YourAppName.TestViewController" let aClass = NSClassFromString(className) as! UIViewController.Type let viewController = aClass.init() 

更新:从testing版6开始,NSStringFromClass将返回你的包名和类名,用点分隔。 所以它会像MyApp.MyClass

Swift类将有一个构build的内部名称,由以下部分构成:

  • 它将从_TtC开始,
  • 后跟一个数字,即你的应用程序名称的长度,
  • 其次是你的应用程序名称,
  • 随着你的class级名字的长度,
  • 其次是你的class级名称。

所以你的类名就像_TtC5MyApp7MyClass

您可以通过执行以下命令将其作为string获取:

 var classString = NSStringFromClass(self.dynamicType) 

在Swift 3中更新,这已经改变为:

 var classString = NSStringFromClass(type(of: self)) 

使用该string,您可以通过执行以下命令来创buildSwift类的实例:

 var anyobjectype : AnyObject.Type = NSClassFromString(classString) var nsobjectype : NSObject.Type = anyobjectype as NSObject.Type var rec: AnyObject = nsobjectype() 

我能够dynamic地实例化一个对象

 var clazz: NSObject.Type = TestObject.self var instance : NSObject = clazz() if let testObject = instance as? TestObject { println("yes!") } 

我还没有find一种方法来从String创buildAnyClass (不使用Obj-C)。 我认为他们不希望你这样做,因为它基本上打破了types系统。

对于swift2,我创build了一个非常简单的扩展来更快地完成这个任务 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) } 

这会得到你想要实例化的类的名字。 然后你可以使用Edwins的答案来实例化你的类的新对象。

从beta 6开始, _stdlib_getTypeName获取variables的损坏types名称。 将其粘贴到一个空的操场上:

 import Foundation class PureSwiftClass { } var myvar0 = NSString() // Objective-C class var myvar1 = PureSwiftClass() var myvar2 = 42 var myvar3 = "Hans" println( "TypeName0 = \(_stdlib_getTypeName(myvar0))") println( "TypeName1 = \(_stdlib_getTypeName(myvar1))") println( "TypeName2 = \(_stdlib_getTypeName(myvar2))") println( "TypeName3 = \(_stdlib_getTypeName(myvar3))") 

输出是:

 TypeName0 = NSString TypeName1 = _TtC13__lldb_expr_014PureSwiftClass TypeName2 = _TtSi TypeName3 = _TtSS 

伊万·斯威克的博客条目有助于破译这些string: http : //www.eswick.com/2014/06/inside-swift/

例如_TtSi代表Swift的内部Inttypes。

在Swift 2.0中(在Xcode 7.01中testing过)_20150930

 let vcName = “HomeTableViewController" let ns = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String // Convert string to class let anyobjecType: AnyObject.Type = NSClassFromString(ns + "." + vcName)! if anyobjecType is UIViewController.Type { // vc is instance let vc = (anyobjecType as! UIViewController.Type).init() print(vc) } 

xcode 7testing版5:

 class MyClass { required init() { print("Hi!") } } if let classObject = NSClassFromString("YOURAPPNAME.MyClass") as? MyClass.Type { let object = classObject.init() } 

我认为我是对的,说你不能,至less不能与目前的testing版(2)。 希望这是未来版本将会改变的东西。

你可以使用NSClassFromString来获取NSClassFromStringtypes的variables,但是在Swift中似乎没有办法实例化它。 你可以使用桥接到Objective C并在那里执行,或者 – 如果它在你的情况下工作 – 回退到使用switch语句 。

显然,在类中只有在运行时才知道这个类是不可能的(在Swift中)实例化一个对象。 对于NSObject的子类,Objective-C包装器是可能的。

至less你可以实例化一个与运行时给定的另一个对象相同的对象,而不需要Objective-C包装器(使用xCode版本6.2 – 6C107a):

  class Test : NSObject {} var test1 = Test() var test2 = test1.dynamicType.alloc() 

在Swift 2.0中(在Xcode 7的beta2中testing),它的工作原理是这样的:

 protocol Init { init() } var type = NSClassFromString(className) as? Init.Type let obj = type!.init() 

当然,来自NSClassFromString的types必须实现这个init协议。

我期望很清楚, className是一个string,其中包含默认不只是“Foo”的类的Obj-C运行时名称,但这个讨论恕我直言,不是你的问题的主要议题。

你需要这个协议,因为默认情况下,所有的Swift类都不执行init方法。

看起来正确的咒语会是…

 func newForName<T:NSObject>(p:String) -> T? { var result:T? = nil if let k:AnyClass = NSClassFromString(p) { result = (k as! T).dynamicType.init() } return result } 

…“p”代表“包装” – 一个明显的问题。

但是从AnyClass到T的关键转换当前会导致编译器崩溃,因此同时必须将k的初始化放入一个单独的闭包中,这个编译很好。

我使用不同的目标,在这种情况下,没有findswift类。 您应该用CFBundleExecutablereplaceCFBundleName。 我也修正了警告:

 - (Class)swiftClassFromString:(NSString *)className { NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"]; NSString *classStringName = [NSString stringWithFormat:@"_TtC%lu%@%lu%@", (unsigned long)appName.length, appName, (unsigned long)className.length, className]; return NSClassFromString(classStringName); } 

来自类的string

 let classString = NSStringFromClass(TestViewController.self) 

要么

 let classString = NSStringFromClass(TestViewController.classForCoder()) 

从string初始化一个UIViewController类:

 let vcClass = NSClassFromString(classString) as! UIViewController.Type let viewController = vcClass.init() 

也在Swift 2.0中(可能之前?)您可以直接使用dynamicType属性访问types

 class User { required init() { // class must have an explicit required init() } var name: String = "" } let aUser = User() aUser.name = "Tom" print(aUser) let bUser = aUser.dynamicType.init() print(bUser) 

产量

 aUser: User = { name = "Tom" } bUser: User = { name = "" } 

适用于我的用例

尝试这个。

 let className: String = String(ControllerName.classForCoder()) print(className) 

我已经这样实施了,

 if let ImplementationClass: NSObject.Type = NSClassFromString(className) as? NSObject.Type{ ImplementationClass.init() } 

我正在使用Swift 3的这个类别:

 // // String+AnyClass.swift // Adminer // // Created by Ondrej Rafaj on 14/07/2017. // Copyright © 2017 manGoweb UK Ltd. All rights reserved. // import Foundation extension String { func convertToClass<T>() -> T.Type? { return StringClassConverter<T>.convert(string: self) } } class StringClassConverter<T> { static func convert(string className: String) -> T.Type? { guard let nameSpace = Bundle.main.infoDictionary?["CFBundleExecutable"] as? String else { return nil } guard let aClass: T.Type = NSClassFromString("\(nameSpace).\(className)") as? T.Type else { return nil } return aClass } } 

用途将是:

 func getViewController(fromString: String) -> UIViewController? { guard let viewController: UIViewController.Type = "MyViewController".converToClass() else { return nil } return viewController.init() } 

这是一个很好的例子:

 class EPRocks { @require init() { } } class EPAwesome : EPRocks { func awesome() -> String { return "Yes"; } } var epawesome = EPAwesome.self(); print(epawesome.awesome);