如何在Swift中打印variables的types或类?

有没有办法在swift中打印variables的运行时types? 例如:

var now = NSDate() var soon = now.dateByAddingTimeInterval(5.0) println("\(now.dynamicType)") // Prints "(Metatype)" println("\(now.dynamicType.description()") // Prints "__NSDate" since objective-c Class objects have a "description" selector println("\(soon.dynamicType.description()") // Compile-time error since ImplicitlyUnwrappedOptional<NSDate> has no "description" method 

在上面的例子中,我正在寻找一种方法来显示variables“很快”的types是ImplicitlyUnwrappedOptional<NSDate> ,或者至lessNSDate!

2016年9月更新

Swift 3.0:使用type(of:) ,例如type(of: someThing) (因为dynamicType关键字已被删除)

2015年10月更新

我更新下面的例子到新的Swift 2.0语法(例如, println被replace为printtoString()现在是String() )。

从Xcode 6.3发行说明

@nschum在评论中指出, Xcode 6.3发布说明显示了另一种方式:

与println或string插值一起使用时,types值现在将打印为完整的demangledtypes名称。

 import Foundation class PureSwiftClass { } var myvar0 = NSString() // Objective-C class var myvar1 = PureSwiftClass() var myvar2 = 42 var myvar3 = "Hans" print( "String(myvar0.dynamicType) -> \(myvar0.dynamicType)") print( "String(myvar1.dynamicType) -> \(myvar1.dynamicType)") print( "String(myvar2.dynamicType) -> \(myvar2.dynamicType)") print( "String(myvar3.dynamicType) -> \(myvar3.dynamicType)") print( "String(Int.self) -> \(Int.self)") print( "String((Int?).self -> \((Int?).self)") print( "String(NSString.self) -> \(NSString.self)") print( "String(Array<String>.self) -> \(Array<String>.self)") 

哪些产出:

 String(myvar0.dynamicType) -> __NSCFConstantString String(myvar1.dynamicType) -> PureSwiftClass String(myvar2.dynamicType) -> Int String(myvar3.dynamicType) -> String String(Int.self) -> Int String((Int?).self -> Optional<Int> String(NSString.self) -> NSString String(Array<String>.self) -> Array<String> 

更新Xcode 6.3:

您可以使用_stdlib_getDemangledTypeName()

 print( "TypeName0 = \(_stdlib_getDemangledTypeName(myvar0))") print( "TypeName1 = \(_stdlib_getDemangledTypeName(myvar1))") print( "TypeName2 = \(_stdlib_getDemangledTypeName(myvar2))") print( "TypeName3 = \(_stdlib_getDemangledTypeName(myvar3))") 

并得到这个输出:

 TypeName0 = NSString TypeName1 = __lldb_expr_26.PureSwiftClass TypeName2 = Swift.Int TypeName3 = Swift.String 

原始答案:

在Xcode 6.3之前, _stdlib_getTypeName得到了一个variables的_stdlib_getTypeNametypes名称。 Ewan Swick的博客文章有助于破译这些string:

例如_TtSi代表Swift的内部Inttypes。

Mike Ash有一篇很棒的博客文章,涵盖了同一主题 。

编辑: 在Swift 1.2(Xcode 6.3)中引入了一个新的toString函数。

您现在可以使用.self和任何使用.dynamicType实例来打印任何types的demangledtypes:

 struct Box<T> {} toString("foo".dynamicType) // Swift.String toString([1, 23, 456].dynamicType) // Swift.Array<Swift.Int> toString((7 as NSNumber).dynamicType) // __NSCFNumber toString((Bool?).self) // Swift.Optional<Swift.Bool> toString(Box<SinkOf<Character>>.self) // __lldb_expr_1.Box<Swift.SinkOf<Swift.Character>> toString(NSStream.self) // NSStream 

尝试调用YourClass.selfyourObject.dynamicType

参考: https : //devforums.apple.com/thread/227425 。

这是你在找什么?

 println("\(object_getClassName(now))"); 

它打印“__NSDate”

更新 :请注意这不再起作用Beta05

我目前的Xcode是版本6.0(6A280e)。

 import Foundation class Person { var name: String; init(name: String) { self.name = name }} class Patient: Person {} class Doctor: Person {} var variables:[Any] = [ 5, 7.5, true, "maple", Person(name:"Sarah"), Patient(name:"Pat"), Doctor(name:"Sandy") ] for variable in variables { let typeLongName = _stdlib_getDemangledTypeName(variable) let tokens = split(typeLongName, { $0 == "." }) if let typeName = tokens.last { println("Variable \(variable) is of Type \(typeName).") } } 

输出:

 Variable 5 is of Type Int. Variable 7.5 is of Type Double. Variable true is of Type Bool. Variable maple is of Type String. Variable Swift001.Person is of Type Person. Variable Swift001.Patient is of Type Patient. Variable Swift001.Doctor is of Type Doctor. 

Swift 3.0

 let string = "Hello" let stringArray = ["one", "two"] let dictionary = ["key": 2] print(type(of: string)) // "String" // Get type name as a string String(describing: type(of: string)) // "String" String(describing: type(of: stringArray)) // "Array<String>" String(describing: type(of: dictionary)) // "Dictionary<String, Int>" // Get full type as a string String(reflecting: type(of: string)) // "Swift.String" String(reflecting: type(of: stringArray)) // "Swift.Array<Swift.String>" String(reflecting: type(of: dictionary)) // "Swift.Dictionary<Swift.String, Swift.Int>" 

从Swift 1.2的Xcode 6.3开始,您可以简单地将types值转换为完整的demangled String

 toString(Int) // "Swift.Int" toString(Int.Type) // "Swift.Int.Type" toString((10).dynamicType) // "Swift.Int" println(Bool.self) // "Swift.Bool" println([UTF8].self) // "Swift.Array<Swift.UTF8>" println((Int, String).self) // "(Swift.Int, Swift.String)" println((String?()).dynamicType)// "Swift.Optional<Swift.String>" println(NSDate) // "NSDate" println(NSDate.Type) // "NSDate.Type" println(WKWebView) // "WKWebView" toString(MyClass) // "[Module Name].MyClass" toString(MyClass().dynamicType) // "[Module Name].MyClass" 

你仍然可以通过className (它返回一个String )来访问这个类。

实际上有几种获取类的方法,例如classForArchiverclassForCoderclassForKeyedArchiver (全部返回AnyClass! )。

你不能得到一个基元的types(一个基元不是一个类)。

例:

 var ivar = [:] ivar.className // __NSDictionaryI var i = 1 i.className // error: 'Int' does not have a member named 'className' 

如果你想获得一个基元的types,你必须使用bridgeToObjectiveC() 。 例:

 var i = 1 i.bridgeToObjectiveC().className // __NSCFNumber 

您可以使用reflection来获取有关对象的信息。
例如对象类的名字:

 var classname = reflect(now).summary

我很幸运:

 let className = NSStringFromClass(obj.dynamicType) 

Xcode 8 Swift 3.0使用types(:)

 let className = "\(type(of: instance))" 

在Xcode 8中,Swift 3.0

脚步:

1.获取types:

选项1:

 let type : Type = MyClass.self //Determines Type from Class 

选项2:

 let type : Type = type(of:self) //Determines Type from self 

2.将types转换为string:

 let string : String = "\(type)" //String 

在Swift 3.0中,可以使用type(of:) ,因为dynamicType关键字已被删除。

SWIFT 3

使用Swift 3的最新版本,我们可以通过String初始值设定项来获得types名称的详细描述。 例如print(String(describing: type(of: object))) 哪里的object 可以是一个实例variables,如数组,字典,一个Int ,一个NSDate ,一个自定义类的实例等

这里是我的完整答案: 在Swift中获取对象的类名作为string

这个问题正在寻找一种方法来获得一个对象的类名作为string,而且,我还提出了另一种方法来获取不是NSObject子类的variables的类名称。 这里是:

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

我做了一个静态函数,它将参数作为Anytypes的对象,并将其类名称返回为String :)。

我用一些variablestesting了这个函数:

  let diccionary: [String: CGFloat] = [:] let array: [Int] = [] let numInt = 9 let numFloat: CGFloat = 3.0 let numDouble: Double = 1.0 let classOne = ClassOne() let classTwo: ClassTwo? = ClassTwo() let now = NSDate() let lbl = UILabel() 

和输出是:

  • diccionary是Dictionary的types
  • 数组的types是Array
  • numInt是Inttypes的
  • numFloat是CGFloattypes的
  • numDouble是Doubletypes的
  • classOne是types:ClassOne
  • classTwo是types:ClassTwo
  • 现在是types:date
  • lbl是types:UILabel

当使用Cocoa(而不是CocoaTouch)时,你可以使用className属性作为NSObject的子类。

 println(now.className) 

这个属性不适用于普通的Swift对象,它不是NSObject的子类(事实上,在Swift中没有root id或对象types)。

 class Person { var name: String? } var p = Person() println(person.className) // <- Compiler error 

在CocoaTouch中,目前没有办法获得给定variablestypes的string描述。 对于Cocoa或CocoaTouch中的原始types,类似的function也不存在。

Swift REPL能够打印出包括它的types在内的值的概要,所以将来可以通过API来实现这种内省方式。

编辑dump(object)似乎做的伎俩。

我已经尝试了一些其他的答案,但是这个问题似乎是关于什么是下属对象。

但是我确实find了一种方法,通过执行以下操作,可以获取对象的Object-C类名称:

 now?.superclass as AnyObject! //replace now with the object you are trying to get the class name for 

这里是你将如何使用它的例子:

 let now = NSDate() println("what is this = \(now?.superclass as AnyObject!)") 

在这种情况下,它将在控制台中打印NSDate。

我发现这个解决scheme,希望可以为别人工作。 我创build了一个类访问值的方法。 请记住,这只适用于NSObject子类。 但至less是一个干净整洁的解决scheme。

 class var className: String!{ let classString : String = NSStringFromClass(self.classForCoder()) return classString.componentsSeparatedByString(".").last; } 

在使用Swift 1.2的最新XCode 6.3中,这是我发现的唯一方法:

 if view.classForCoder.description() == "UISegment" { ... } 

在testing版5的lldb中,您可以使用以下命令查看对象的类:

 fr v -dr shipDate 

其输出如下所示:

 (DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940 

命令扩展出来的意思就是:

Frame Variable (打印框架variables) -d run_target (展开dynamictypes)

有用的知道是,使用“框架variables”输出variables值保证没有代码执行。

我find了自主开发的类解决scheme (或者你有权访问)。

在您的对象类定义中放置下面的计算属性

 var className: String? { return __FILE__.lastPathComponent.stringByDeletingPathExtension } 

现在,您可以简单地调用对象的类名称,如下所示:

 myObject.className 

请注意,这只有在您的类定义是在一个与您想要的名称类完全相同的文件内进行时才有效

由于这是通常的情况,上面的答案应该在大多数情况下 。 但在某些特殊情况下,您可能需要找出不同的解决scheme。


如果你需要类(文件)本身的类名你可以简单地使用这一行:

 let className = __FILE__.lastPathComponent.stringByDeletingPathExtension 

也许这种方法可以帮助一些人。

根据上面的Klass和Kevin Ballard的回答和评论,我会select:

 println(_stdlib_getDemangledTypeName(now).componentsSeparatedByString(".").last!) println(_stdlib_getDemangledTypeName(soon).componentsSeparatedByString(".").last!) println(_stdlib_getDemangledTypeName(soon?).componentsSeparatedByString(".").last!) println(_stdlib_getDemangledTypeName(soon!).componentsSeparatedByString(".").last!) println(_stdlib_getDemangledTypeName(myvar0).componentsSeparatedByString(".").last!) println(_stdlib_getDemangledTypeName(myvar1).componentsSeparatedByString(".").last!) println(_stdlib_getDemangledTypeName(myvar2).componentsSeparatedByString(".").last!) println(_stdlib_getDemangledTypeName(myvar3).componentsSeparatedByString(".").last!) 

这将打印出来:

 "NSDate" "ImplicitlyUnwrappedOptional" "Optional" "NSDate" "NSString" "PureSwiftClass" "Int" "Double" 
 let i: Int = 20 func getTypeName(v: Any) -> String { let fullName = _stdlib_demangleName(_stdlib_getTypeName(i)) if let range = fullName.rangeOfString(".") { return fullName.substringFromIndex(range.endIndex) } return fullName } println("Var type is \(getTypeName(i)) = \(i)") 

这里的许多答案不能用最新的Swift(在编写本文时是Xcode 7.1.1)。

目前获取信息的方法是创build一个Mirror并询问这个信息。 对于类名来说,它很简单:

 let mirror = Mirror(reflecting: instanceToInspect) let classname:String = mirror.description 

有关该对象的其他信息也可以从Mirror检索。 有关详细信息,请参阅http://swiftdoc.org/v2.1/type/Mirror/

似乎没有通用的方法来打印任意值types的types名称。 正如其他人已经指出的,对于实例,你可以打印value.className但对于原始值,似乎在运行时,types信息已经消失。

例如,它看起来好像没有办法键入: 1.something()并获取任何值的Int 。 (你可以像另一个回答build议的那样,使用i.bridgeToObjectiveC().className给你一个提示,但是__NSCFNumber实际上并不是 i的types – 只是当它跨过Objective- C函数调用。)

我会很高兴被certificate是错误的,但它看起来像types检查都是在编译时完成的,就像C ++(禁用了RTTI),许多types信息在运行时不见了。

不完全是你以后,但你也可以检查variables的types对Swifttypes如下所示:

 let object: AnyObject = 1 if object is Int { } else if object is String { } 

例如。

Xcode 7.3.1,Swift 2.2:

String(instanceToPrint.self).componentsSeparatedByString(".").last

Swift 3.0,Xcode 8

用下面的代码你可以问一个实例的类。 你也可以比较两个实例,有相同的类。

 // CREATE pure SWIFT class class MySwiftClass { var someString : String = "default" var someInt : Int = 5 } // CREATE instances let firstInstance = MySwiftClass() let secondInstance = MySwiftClass() secondInstance.someString = "Donald" secondInstance.someInt = 24 // INSPECT instances if type(of: firstInstance) === MySwiftClass.self { print("SUCCESS with ===") } else { print("PROBLEM with ===") } if type(of: firstInstance) == MySwiftClass.self { print("SUCCESS with ==") } else { print("PROBLEM with ==") } // COMPARE CLASS OF TWO INSTANCES if type(of: firstInstance) === type(of: secondInstance) { print("instances have equal class") } else { print("instances have NOT equal class") } 

最好的答案是没有一个新的方式来使用type(of:的工作示例。为了帮助像我这样的新手,这里是一个工作的例子,主要从苹果的文档 – https://developer.apple的;.com /文档/迅速/ 2885064型

 doubleNum = 30.1 func printInfo(_ value: Any) { let varType = type(of: value) print("'\(value)' of type '\(varType)'") } printInfo(doubleNum) //'30.1' of type 'Double' 

这在检查对象是否是类的types时也很方便:

 if someObject is SomeClass { //someObject is a type of SomeClass } 

请看下面的代码片段,让我知道如果你正在寻找像下面的东西或不。

 var now = NSDate() var soon = now.addingTimeInterval(5.0) var nowDataType = Mirror(reflecting: now) print("Now is of type: \(nowDataType.subjectType)") var soonDataType = Mirror(reflecting: soon) print("Soon is of type: \(soonDataType.subjectType)") 

影响从String(describing: type(of: self))返回的类名的另一个重要方面是Access Control

考虑下面的例子,基于Swift 3.1.1Xcode 8.3.3 (2017年7月)

 func printClassNames() { let className1 = SystemCall<String>().getClassName() print(className1) // prints: "SystemCall<String>" let className2 = DemoSystemCall().getClassName() print(className2) // prints: "DemoSystemCall" // private class example let className3 = PrivateDemoSystemCall().getClassName() print(className3) // prints: "(PrivateDemoSystemCall in _0FC31E1D2F85930208C245DE32035247)" // fileprivate class example let className4 = FileprivateDemoSystemCall().getClassName() print(className4) // prints: "(FileprivateDemoSystemCall in _0FC31E1D2F85930208C245DE32035247)" } class SystemCall<T> { func getClassName() -> String { return String(describing: type(of: self)) } } class DemoSystemCall: SystemCall<String> { } private class PrivateDemoSystemCall: SystemCall<String> { } fileprivate class FileprivateDemoSystemCall: SystemCall<String> { } 

正如你所看到的,这个例子中的所有类都具有不同级别的访问控制,这影响了它们的String表示。 如果这些类具有privatefileprivate访问控制级别,Swift似乎会添加一些与所讨论的类的“嵌套”类有关的标识符。

PrivateDemoSystemCallFileprivateDemoSystemCall的结果是附加了相同的标识符,因为它们都嵌套在同一个父类中。

我还没有find一种方法来摆脱,除了一些hackyreplace或正则expression式的function。

只是我2美分。