是否有一种方法可以在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

在上面的例子中,我正在寻找一种方法来显示变量“soon”的类型是ImplicitlyUnwrappedOptional<NSDate>,或至少NSDate!


当前回答

我为自己开发的类(或您可以访问的类)找到了一个解决方案。

在你的对象类定义中放置以下计算属性:

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"

斯威夫特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>"

斯威夫特5

在Swift 3的最新版本中,我们可以通过String初始化器获得对类型名称的详细描述。例如,print(String(description: type(of: object)))。其中object可以是一个实例变量,如数组、字典、Int、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()

结果是:

Dictionary的类型为Dictionary array的类型是array numInt是Int类型 numFloat类型为CGFloat numDouble是Double类型 classOne的类型为:classOne classTwo的类型为:classTwo now的类型是:日期 lbl类型为:UILabel

斯威夫特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"

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

考虑以下例子,基于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表示。如果类有私有或文件私有的访问控制级别,Swift似乎会附加一些与类的“嵌套”类相关的标识符。

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

我还没有找到一种方法来摆脱,除了一些hack替换或正则表达式函数。

这只是我的个人意见。