有没有办法快速打印变量的运行时类型?例如:
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
在上面的示例中,我正在寻找一种方法来表明变量“soon”的类型为 ImplicitlyUnwrappedOptional<NSDate>
,或者至少为 NSDate!
。
2016 年 9 月更新
Swift 3.0:使用 type(of:)
,例如 type(of: someThing)
(因为 dynamicType
关键字已被删除)
2015 年 10 月更新:
我将下面的示例更新为新的 Swift 2.0 语法(例如,println
被替换为 print
,toString()
现在是 String()
)。
来自 Xcode 6.3 发行说明:
@nschum 在评论中指出 Xcode 6.3 release notes 显示了另一种方式:
当与 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 有助于破译这些字符串:
例如 _TtSi
代表 Swift 的内部 Int
类型。
Mike Ash has a great blog entry covering the same topic。
编辑:新的 toString
函数 has been introduced in Swift 1.2 (Xcode 6.3)。
您现在可以使用 .self
打印任何类型的解组后类型,并使用 .dynamicType
打印任何实例:
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.self
和 yourObject.dynamicType
。
参考:https://devforums.apple.com/thread/227425。
someInstance.dynamicType.printClassName()
将打印类的名称。
斯威夫特 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>"
这是你要找的吗?
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.
Optional(...)
中,因此您的代码只会返回 Optional
作为 Type。它还应该将 var optionalTestVar: Person? = Person(name:"Sarah")
显示为 Optional(Person) 和带有 Person 的 var!作为 ImplicitlyUnwrappedOptional(Person)
从带有 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"
您仍然可以通过 className
(返回 String
)访问该类。
获取类实际上有几种方法,例如classForArchiver
、classForCoder
、classForKeyedArchiver
(都返回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
import Cocoa
。
className
是 Cocoa 的 AppleScript 支持的一部分,绝对不应该用于通用内省。显然它在 iOS 上不可用。
您可以使用反射来获取有关对象的信息。例如对象类的名称:
var classname = reflect(now).summary
reflect(x).summary
- 谢谢!
Xcode 8 Swift 3.0 使用 type(of:)
let className = "\(type(of: instance))"
我很幸运:
let className = NSStringFromClass(obj.dynamicType)
在 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. 将类型转换为字符串:
let string : String = "\(type)" //String
在 Swift 3.0 中,您可以使用 type(of:)
,因为 dynamicType
关键字已被删除。
斯威夫特 5
在最新版本的 Swift 3 中,我们可以通过 String
初始化程序获得类型名称的漂亮描述。例如,print(String(describing: type(of: object)))
。其中 object
可以是实例变量,例如数组、字典、Int
、NSDate
、自定义类的实例等。
这是我的完整答案: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()
输出是:
字典是字典类型
数组是数组类型
numInt 是 Int 类型
numFloat 是 CGFloat 类型
numDouble 是 Double 类型
classOne 的类型:ClassOne
classTwo 的类型:ClassTwo
现在是类型:日期
lbl 的类型:UILabel
使用 Cocoa(不是 CocoaTouch)时,您可以将 className
属性用于作为 NSObject 子类的对象。
println(now.className)
该属性不适用于普通的 Swift 对象,它们不是 NSObject 的子类(事实上,Swift 中没有根 id 或对象类型)。
class Person {
var name: String?
}
var p = Person()
println(person.className) // <- Compiler error
在 CocoaTouch 中,此时没有办法获取给定变量类型的字符串描述。 Cocoa 或 CocoaTouch 中的原始类型也不存在类似的功能。
Swift REPL 能够打印出包括其类型在内的值的摘要,因此这种自省方式有可能在未来通过 API 实现。
编辑:dump(object)
似乎可以解决问题。
dump(object)
也非常强大。谢谢你。
最佳答案没有使用 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'
我在这里尝试了其他一些答案,但 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。
我找到了这个解决方案,希望它可能适用于其他人。我创建了一个类方法来访问该值。请记住,这仅适用于 NSObject 子类。但至少是一个干净整洁的解决方案。
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" {
...
}
<swift module name>.<actual class name>
格式返回类名,因此您想用 .
拆分字符串并获取最后一个标记。
这里的许多答案不适用于最新的 Swift(撰写本文时为 Xcode 7.1.1)。
当前获取信息的方法是创建一个 Mirror
并询问它。对于类名,它很简单:
let mirror = Mirror(reflecting: instanceToInspect)
let classname:String = mirror.description
还可以从 Mirror
检索有关对象的其他信息。有关详细信息,请参阅 http://swiftdoc.org/v2.1/type/Mirror/。
要在 Swift 中获取对象类型或对象类,必须使用 type(of: yourObject)
类型(属于:你的对象)
在 beta 5 的 lldb 中,您可以使用以下命令查看对象的类:
fr v -d r shipDate
输出类似:
(DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940
扩展的命令意味着类似:
Frame Variable
(打印帧变量)-d run_target
(扩展动态类型)
需要了解的一点是,使用“帧变量”输出变量值可以保证不执行任何代码。
我找到了自开发课程的解决方案(或者您可以访问的课程)。
将以下计算属性放在您的对象类定义中:
var className: String? {
return __FILE__.lastPathComponent.stringByDeletingPathExtension
}
现在您可以像这样简单地调用对象上的类名:
myObject.className
请注意,这仅在您的类定义是在与您想要的类名称完全相同的文件中进行时才有效。
由于这通常是这种情况,因此上述答案应该适用于大多数情况。但在某些特殊情况下,您可能需要找出不同的解决方案。
如果您需要类(文件)本身中的类名,您可以简单地使用这一行:
let className = __FILE__.lastPathComponent.stringByDeletingPathExtension
也许这种方法可以帮助一些人。
根据上面 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"
toString(self.dynamicType).componentsSeparatedByString(".").last!
,显然我在对象上下文中并且能够引用 self
。
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)")
斯威夫特版本 4:
print("\(type(of: self)) ,\(#function)")
// within a function of a class
谢谢@Joshua Dance
斯威夫特 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"
似乎没有通用的方法来打印任意值类型的类型名称。正如其他人所指出的,对于 class 实例,您可以打印 value.className
但对于原始值,在运行时似乎类型信息消失了。
例如,看起来好像没有办法输入:1.something()
并为 something
的任何值输出 Int
。 (正如另一个答案所建议的那样,您可以使用 i.bridgeToObjectiveC().className
给您一个提示,但 __NSCFNumber
不是实际上是 i
的类型 - 只是当它转换为跨越了 Objective-C 函数调用的边界。)
我很高兴被证明是错误的,但看起来类型检查都是在编译时完成的,并且像 C++(禁用 RTTI)一样,大部分类型信息在运行时都消失了。
这是您获取对象或类型的类型字符串的方式,该字符串是一致的,并考虑到对象定义属于或嵌套在哪个模块中。适用于 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
不完全是您所追求的,但您还可以根据 Swift 类型检查变量的类型,如下所示:
let object: AnyObject = 1
if object is Int {
}
else if object is String {
}
例如。
Xcode 7.3.1,斯威夫特 2.2:
String(instanceToPrint.self).componentsSeparatedByString(".").last
_stdlib_getTypeName()
的?集成的 REPL 不再存在,swift-ide-test
也不存在,并且 Xcode 的 Swift 模块打印省略了以_
为前缀的值。lldb
的符号。还有_stdlib_getDemangledTypeName()
和_stdlib_demangleName()
。image
是target modules
的快捷方式。我最终使用了target modules lookup -r -n _stdlib_
,当然更好地表达为image lookup -r -n _stdlib_ libswiftCore.dylib
dynamicType
关键字已从 Swift 中删除。取而代之的是一个新的原始函数type(of:)
已添加到语言中:github.com/apple/swift/blob/master/CHANGELOG.md