在Swift中获取对象的类名作为string

获取对象的类名作为string使用

object_getClassName(myViewController) 

返回像这样的东西

 _TtC5AppName22CalendarViewController 

我正在寻找纯粹的版本:“CalendarViewController”。 我如何得到清理的类名string?

我发现了一些关于这个问题的尝试,但不是一个真正的答案。 这不可能吗?

来自实例的string,例如myViewController

 String(describing: type(of: myViewController)) 

来自types的string,例如MyViewController

 String(describing: MyViewController.self) 

编辑:更新为斯威夫特3,谢谢@AmitaiB

更新到SWIFT 3

我们可以通过String初始值设定项使用实例variables获得types名称的详细描述,并创build某个类的新对象

例如print(String(describing: type(of: object))) object可以是一个实例variables,如数组,字典, IntNSDate

因为NSObject是大多数Objective-C类层次结构的根类,所以你可以尝试为NSObject做一个扩展来获取NSObject的每个子类的类名。 喜欢这个:

 extension NSObject { var theClassName: String { return NSStringFromClass(type(of: self)) } } 

或者你可以创build一个参数types为Any的静态函数(所有types都隐式符合的协议),并返回类名为String。 喜欢这个:

 class Utility{ class func classNameAsString(obj: Any) -> String { //prints more readable results for dictionaries, arrays, Int, etc return String(describing: type(of: obj)) } } 

现在你可以做这样的事情:

 class ClassOne : UIViewController{ // some code here } class ClassTwo : ClassOne{ // some code here } class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Get the class name as String let dictionary: [String: CGFloat] = [:] let array: [Int] = [] let int = 9 let numFloat: CGFloat = 3.0 let numDouble: Double = 1.0 let classOne = ClassOne() let classTwo: ClassTwo? = ClassTwo() let now = NSDate() let lbl = UILabel() print("diccionary: [String: CGFloat] = [:] -> \(Utility.classNameAsString(diccionary))") print("array: [Int] = [] -> \(Utility.classNameAsString(array))") print("int = 9 -> \(Utility.classNameAsString(int))") print("numFloat: CGFloat = 3.0 -> \(Utility.classNameAsString(numFloat))") print("numDouble: Double = 1.0 -> \(Utility.classNameAsString(numDouble))") print("classOne = ClassOne() -> \((ClassTwo?).self)") //we use the Extension if classTwo != nil { print("classTwo: ClassTwo? = ClassTwo() -> \(Utility.classNameAsString(classTwo!))") //now we can use a Forced-Value Expression and unwrap the value } print("now = Date() -> \(Utility.classNameAsString(now))") print("lbl = UILabel() -> \(String(describing: type(of: lbl)))") // we use the String initializer directly } } 

另外,一旦我们可以获得类名称作为string, 我们可以instanciate该类的新对象

 // Instanciate a class from a String print("\nInstaciate a class from a String") let aClassName = classOne.theClassName let aClassType = NSClassFromString(aClassName) as! NSObject.Type let instance = aClassType.init() // we create a new object print(String(cString: class_getName(type(of: instance)))) print(instance.self is ClassOne) 

也许这可以帮助那里的人!

Swift 3.1

这是将className作为variables(用于实例或类对象)的扩展。

 extension NSObject { var className: String { return String(describing: type(of: self)) } class var className: String { return String(describing: self) } } 

如何使用:

 print(self.className) print(ViewController.className) 

Swift 3.0

String(describing: MyViewController.self)

我build议这样一个方法( 非常Swifty ):

 // Swift 3 func typeName(_ some: Any) -> String { return (some is Any.Type) ? "\(some)" : "\(type(of: some))" } // Swift 2 func typeName(some: Any) -> String { return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)" } 

它不使用内省或手动解锁( 没有魔法! )。


这里是一个演示:

 // Swift 3 import class Foundation.NSObject func typeName(_ some: Any) -> String { return (some is Any.Type) ? "\(some)" : "\(type(of: some))" } class GenericClass<T> { var x: T? = nil } protocol Proto1 { func f(x: Int) -> Int } @objc(ObjCClass1) class Class1: NSObject, Proto1 { func f(x: Int) -> Int { return x } } struct Struct1 { var x: Int } enum Enum1 { case X } print(typeName(GenericClass<Int>.self)) // GenericClass<Int> print(typeName(GenericClass<Int>())) // GenericClass<Int> print(typeName(Proto1.self)) // Proto1 print(typeName(Class1.self)) // Class1 print(typeName(Class1())) // Class1 print(typeName(Class1().f)) // (Int) -> Int print(typeName(Struct1.self)) // Struct1 print(typeName(Struct1(x: 1))) // Struct1 print(typeName(Enum1.self)) // Enum1 print(typeName(Enum1.X)) // Enum1 

如果你有typesFoo ,下面的代码会给你Swift 3和Swift 4中的"Foo"

 let className = String(describing: Foo.self) // Gives you "Foo" 

这里的大部分答案的问题是,当你没有任何types的实例时,他们给你"Foo.Type"作为结果string,而你真正想要的只是"Foo" 。 下面给你"Foo.Type" ,正如其他一些答案中提到的那样。

 let className = String(describing: type(of: Foo.self)) // Gives you "Foo.Type" 

如果你只是想要"Foo"那么type(of:)部分的type(of:)是不必要的。

您可以像这样使用名为_stdlib_getDemangledTypeName的Swift标准库函数:

 let name = _stdlib_getDemangledTypeName(myViewController) 

也可以使用镜像:

 let vc = UIViewController() String(Mirror(reflecting: vc).subjectType) 

NB:这个方法也可以用于Structs和Enums。 有一个displayStyle显示了什么types的结构:

 Mirror(reflecting: vc).displayStyle 

返回是一个枚举,所以你可以:

 Mirror(reflecting: vc).displayStyle == .Class 

你可以试试这个方法:

  self.classForCoder.description() 

Swift 3.0:你可以创build一个像这样的扩展。它给出没有项目名称的类名称

 extension NSObject { var className: String { return NSStringFromClass(self as! AnyClass).components(separatedBy: ".").last ?? "" } public class var className: String { return NSStringFromClass(self).components(separatedBy: ".").last ?? "" } } 

要在Swift 4中获得types名称(我没有检查早期版本),只需要使用string插值:

 "\(type(of: myViewController))" 

你可以在一个types本身上使用.self ,并且在一个实例上使用type(of:_) .self函数的type(of:_)

 // Both constants will have "UIViewController" as their value let stringFromType = "\(UIViewController.self)" let stringFromInstance = "\(type(of: UIViewController()))" 

我一直在寻找这个答案和一段时间。 我使用GKStateMachine并且喜欢观察状态变化,想要一个简单的方法来查看类名。 我不确定是否只是iOS 10或Swift 2.3,但是在那个环境下,下面是我想要的:

 let state:GKState? print("Class Name: \(String(state.classForCoder)") // Output: // Class Name: GKState 

尝试对类self或instance dynamicType进行reflect().summary 。 在获取dynamicType之前解包可选项,否则dynamicType是可选包装器。

 class SampleClass { class InnerClass{} } let sampleClassName = reflect(SampleClass.self).summary; let instance = SampleClass(); let instanceClassName = reflect(instance.dynamicType).summary; let innerInstance = SampleClass.InnerClass(); let InnerInstanceClassName = reflect(innerInstance.dynamicType).summary.pathExtension; let tupleArray = [(Int,[String:Int])](); let tupleArrayTypeName = reflect(tupleArray.dynamicType).summary; 

摘要是一个描述了generics类的类path。 要从摘要中获得简单的类名,请尝试使用此方法。

 func simpleClassName( complexClassName:String ) -> String { var result = complexClassName; var range = result.rangeOfString( "<" ); if ( nil != range ) { result = result.substringToIndex( range!.startIndex ); } range = result.rangeOfString( "." ); if ( nil != range ) { result = result.pathExtension; } return result; } 

Swift 3.0(macOS 10.10和更高版本),你可以从className中得到它

 self.className.components(separatedBy: ".").last! 

我用Swift 3在Playground中尝试了type(of:...) 。这是我的结果。 这是代码格式版本。

 print(String(describing: type(of: UIButton.self))) print(String(describing: type(of: UIButton()))) UIButton.Type UIButton 

以String的forms获取类名,如下所示

 @objc(YourClassName) class YourClassName{} 

并使用以下语法获得类名称

 NSStringFromClass(YourClassName) 

我在Swift 2.2中使用它

 guard let currentController = UIApplication.topViewController() else { return } currentController.classForCoder.description().componentsSeparatedByString(".").last! 

有时候,其他的解决scheme会根据你试图查看的对象给出一个无用的名字。 在这种情况下,您可以使用以下命令将类名称作为string获取。

 String(cString: object_getClassName(Any!)) 

⌘点击xcode中的函数可以看到一些相当有用的相关方法。 或在这里检查https://developer.apple.com/reference/objectivec/objective_c_functions

上述解决scheme不适合我。 主要产生的问题在几个评论中提到:

MyAppName.ClassName

要么

MyFrameWorkName.ClassName

这个解决scheme在Xcode 9,Swift 3.0上工作:

我将它命名为classNameCleaned以便访问更容易,并且与将来的className()更改不冲突:

 extension NSObject { static var classNameCleaned : String { let className = self.className() if className.contains(".") { let namesArray = className.components(separatedBy: ".") return namesArray.last ?? className } else { return self.className() } } 

}

用法:

 NSViewController.classNameCleaned MyCustomClass.classNameCleaned 

如果你不喜欢这个蹩脚的名字,你可以指定你自己的名字:

 @objc(CalendarViewController) class CalendarViewController : UIViewController { // ... } 

然而,从长远来看,要学会分析被打乱的名字会更好。 格式是标准和有意义的,不会改变。