如何在Swift中打印变量的类型或类?

时间:2014-06-03 02:24:43

标签: swift types

有没有办法在swift中打印变量的运行时类型?例如:

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

在上面的示例中,我正在寻找一种方法来显示变量&#34;很快&#34;属于ImplicitlyUnwrappedOptional<NSDate>类型,或至少为NSDate!

34 个答案:

答案 0 :(得分:357)

2016年9月更新

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

2015年10月更新

我将以下示例更新为新的Swift 2.0语法(例如,println已替换为printtoString()现已为String()。)

来自Xcode 6.3发行说明

@nschum在评论中指出Xcode 6.3 release notes显示另一种方式:

  

当使用时,类型值现在打印为完整的demangled类型名称   println或字符串插值。

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获得了变量的错位类型名称。 Ewan Swick's blog entry有助于破译这些字符串:

e.g。 _TtSi代表Swift的内部Int类型。

Mike Ash has a great blog entry covering the same topic

答案 1 :(得分:45)

修改:新的toString函数has been introduced in Swift 1.2 (Xcode 6.3)

您现在可以使用.self以及使用.dynamicType的任何实例打印任何类型的demangled类型:

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

答案 2 :(得分:30)

这是你正在寻找的吗?

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

打印&#34; __ NSDate&#34;

更新:请注意,从Beta05开始,这似乎不再起作用

答案 3 :(得分:30)

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>"

答案 4 :(得分:23)

我目前的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.

答案 5 :(得分:18)

从使用Swift 1.2的Xcode 6.3开始,您只需将类型值转换为完全解码的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"

答案 6 :(得分:17)

您仍然可以通过className(返回String)来访问该课程。

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

您无法获得基元的类型(基元类)。

示例:

var ivar = [:]
ivar.className // __NSDictionaryI

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

如果要获取基元的类型,则必须使用bridgeToObjectiveC()。例如:

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

答案 7 :(得分:16)

您可以使用反射获取有关对象的信息 例如,对象类的名称:

var classname = reflect(now).summary

答案 8 :(得分:13)

我好运:

let className = NSStringFromClass(obj.dynamicType)

答案 9 :(得分:12)

Xcode 8 Swift 3.0使用类型(of :)

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

答案 10 :(得分:10)

在Xcode 8中,Swift 3.0

步骤:

1。获取类型:

选项1:

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

选项2:

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

2。将Type转换为String:

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

答案 11 :(得分:8)

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

答案 12 :(得分:6)

SWIFT 5

使用最新版本的Swift 3,我们可以通过String初始化程序获得关于类型名称的详细描述。例如,print(String(describing: type(of: object)))。其中object 可以是实例变量,如数组,字典,IntNSDate,自定义类的实例等。

以下是我的完整答案:Get class name of object as string in Swift

这个问题是寻找一种方法来获取对象的类名作为字符串,但我也提出了另一种方法来获取不是NSObject的子类的变量的类名。这是:

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

我创建了一个静态函数,它将Any类型的对象作为参数,并将其类名返回为String :)。

我用一些变量测试了这个函数,如:

    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
  • 数组的类型为Array
  • numInt的类型为Int
  • numFloat的类型为CGFloat
  • numDouble的类型为Double
  • classOne的类型为:ClassOne
  • classTwo的类型为:ClassTwo
  • 现在的类型为:日期
  • lbl的类型为:UILabel

答案 13 :(得分:5)

使用Cocoa(不是CocoaTouch)时,可以将className属性用于作为NSObject子类的对象。

println(now.className)

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

class Person {
    var name: String?
}

var p = Person()
println(person.className) // <- Compiler error

在CocoaTouch中,目前还没有办法获得给定变量类型的字符串描述。 Cocoa或CocoaTouch中的原始类型也不存在类似的功能。

Swift REPL能够打印出包括其类型在内的值的摘要,因此将来可以通过API实现这种内省。

编辑 dump(object)似乎可以解决问题。

答案 14 :(得分:5)

最佳答案并未提供使用type(of:执行此操作的新方式的实例。所以为了帮助像我这样的新手,这是一个有效的例子,主要来自Apple的文档 - https://developer.apple.com/documentation/swift/2885064-type

doubleNum = 30.1

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

printInfo(doubleNum)
//'30.1' of type 'Double'

答案 15 :(得分:4)

在最新的带有Swift 1.2的XCode 6.3中,这是我找到的唯一方法:

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

答案 16 :(得分:4)

这里的许多答案都不适用于最新的Swift(编写本文时的Xcode 7.1.1)。

获取信息的当前方式是创建Mirror并询问该信息。对于classname,它很简单:

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

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

答案 17 :(得分:4)

我已经尝试了其他一些答案,但是milage似乎非常关注底层物体是什么。

但是我确实找到了一种方法,你可以通过执行以下操作来获取对象的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。

答案 18 :(得分:4)

我发现这个解决方案有望为其他人服务。 我创建了一个类方法来访问该值。请记住,这只适用于NSObject子类。但至少是一个干净整洁的解决方案。

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

答案 19 :(得分:3)

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)")

答案 20 :(得分:3)

根据上面Klass和Kevin Ballard给出的答案和评论,我会选择:

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"

答案 21 :(得分:3)

我找到了自行开发课程的解决方案(或者您有权访问)。

将以下计算属性放在对象类定义中:

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

现在您只需在对象上调用类名称即可:

myObject.className

请注意,只有在您的类定义是在名为完全的文件中进行时才会有效,就像您想要名称的类一样。

因为 但在某些特殊情况下,您可能需要找出不同的解决方案。


如果您需要班级(文件)本身的班级名称 ,您只需使用此行:

let className = __FILE__.lastPathComponent.stringByDeletingPathExtension

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

答案 22 :(得分:3)

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

fr v -d r shipDate

输出如下内容:

(DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940

展开的命令意味着:

Frame Variable(打印一个帧变量)-d run_target(展开动态类型)

有用的东西是使用&#34; Frame Variable&#34;输出变量值保证不执行代码。

答案 23 :(得分:3)

Swift版本4:

print("\(type(of: self)) ,\(#function)")
// within a function of a class

谢谢@Joshua Dance

答案 24 :(得分:2)

雨燕4:

// "TypeName"
func stringType(of some: Any) -> String {
    let string = (some is Any.Type) ? String(describing: some) : String(describing: type(of: some))
    return string
}

// "ModuleName.TypeName"
func fullStringType(of some: Any) -> String {
    let string = (some is Any.Type) ? String(reflecting: some) : String(reflecting: type(of: some))
    return string
}

用法:

print(stringType(of: SomeClass()))     // "SomeClass"
print(stringType(of: SomeClass.self))  // "SomeClass"
print(stringType(of: String()))        // "String"
print(fullStringType(of: String()))    // "Swift.String"

答案 25 :(得分:2)

这是您获取一致并考虑到模块的对象类型的类型字符串的方式对象定义属于或嵌套在其中。在Swift 4.x中可用。

@inline(__always) func typeString(for _type: Any.Type) -> String {
    return String(reflecting: type(of: _type))
}

@inline(__always) func typeString(for object: Any) -> String {
    return String(reflecting: type(of: type(of: object)))
}

struct Lol {
    struct Kek {}
}

// if you run this in playground the results will be something like
typeString(for: Lol.self)    //    __lldb_expr_74.Lol.Type
typeString(for: Lol())       //    __lldb_expr_74.Lol.Type
typeString(for: Lol.Kek.self)//    __lldb_expr_74.Lol.Kek.Type
typeString(for: Lol.Kek())   //    __lldb_expr_74.Lol.Kek.Type

答案 26 :(得分:2)

似乎没有通用的方法来打印任意值类型的类型名称。正如其他人已经注意到的,对于 class 实例,您可以打印value.className但是对于原始值,似乎在运行时,类型信息消失了。

例如,看起来似乎没有办法输入1.something()并且Int获取something的任何值。 (正如另一个答案建议,你可以使用i.bridgeToObjectiveC().className给你一个提示,但__NSCFNumber 实际上是i的类型 - 只是它是什么当它越过Objective-C函数调用的边界时将被转换为。)

我很高兴被证明是错误的,但看起来类型检查都是在编译时完成的,并且像C ++一样(禁用RTTI)很多类型信息在运行时都消失了。

答案 27 :(得分:1)

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")
}

答案 28 :(得分:1)

要在 Swift 中获得类型的对象对象类,您必须使用类型(of:yourObject)

type(of:yourObject)

答案 29 :(得分:1)

Xcode 7.3.1,Swift 2.2:

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

答案 30 :(得分:1)

不完全是你所追求的,但你也可以检查Swift类型的变量类型,如下所示:

let object: AnyObject = 1

if object is Int {
}
else if object is String {
}

例如。

答案 31 :(得分:0)

影响从String(describing: type(of: self))返回的班级名称的另一个重要方面是访问控制

请考虑以下示例,基于 Swift 3.1.1 Xcode 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似乎会附加某种与&#34;嵌套相关的标识符&#34;有问题的班级。

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

除了一些hacky替换或正则表达式函数之外,我还没有找到摆脱它的方法。

只需2美分。

答案 32 :(得分:0)

请查看以下代码段,如果您正在寻找以下内容,请与我们联系。

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)")

答案 33 :(得分:0)

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

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