有没有办法在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 ImplicitlyUnwrappedOptionalhas no "description" method
在上面的例子中,我正在寻找一种方法来显示变量"很快"是类型ImplicitlyUnwrappedOptional
,或至少NSDate!
.
编辑:Swift 1.2(Xcode 6.3)中引入了一个新toString
功能.
现在,您可以打印demangled类型使用任何类型的.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.
这是你在找什么?
println("\(object_getClassName(now))");
它打印"__NSDate"
更新:请注意,这似乎不再适用于Beta05
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发行说明显示了另一种方式:
现在,当与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的博客文章有助于破译这些字符串:
例如_TtSi
代表Swift的内部Int
类型.
Mike Ash有一篇很棒的博客文章,涵盖了相同的主题.
我目前的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.
您仍然可以通过className
(返回a 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
从使用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"
您可以使用反射来获取有关对象的信息.
例如对象类的名称:
var classname = reflect(now).summary
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 3.0中,您可以使用type(of:)
,因为dynamicType
关键字已被删除.
我好运:
let className = NSStringFromClass(obj.dynamicType)
let type : Type = MyClass.self //Determines Type from Class
let type : Type = type(of:self) //Determines Type from self
let string : String = "\(type)" //String
Xcode 8 Swift 3.0使用类型(:)
let className = "\(type(of: instance))"
SWIFT 3
使用最新版本的Swift 3,我们可以通过String
初始化程序获得类型名称的漂亮描述.比如,例如print(String(describing: type(of: object)))
.哪里object
可以是实例变量,如数组,字典,a Int
,a NSDate
,自定义类的实例等.
这是我的完整答案:在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的类型为Array
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)
似乎可以解决问题。
最佳答案没有使用新方法的工作示例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'