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

365

有没有一种方法可以在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!的方法。

48
@JasonMArcher告诉我这个问题怎么是重复的,如果你链接的那个问题是在这个问题之后4天才被问到的? - akashivskyy
有关测试Swift对象类型或读取Swift对象类型的问题有很多。我们正在寻找最佳的问题作为该主题的“主问题”。建议的重复问题有更详细的答案。这并不是说你做错了什么,只是我们试图减少混乱。 - JasonMArcher
4
建议的重复问题并没有回答相同的问题;Type.self不能被打印到控制台用于调试目的,它应该被用于传递给其他将类型作为对象使用的函数。 - Matt Bridges
2
OT:非常奇怪,Swift没有提供这个功能,而且人们需要在这样的低级C库中摆弄。值得提交错误报告吗? - qwerty_so
各位,我已经提供了我的答案。请看一下并让我知道是否符合预期。 - DILIP KOSURI
34个回答

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

0

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

考虑以下基于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,结果是附加了相同的标识符,因为它们都嵌套在同一个父类中。

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

仅供参考。


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

0

当检查一个对象是否是某个类的类型时,这也非常方便:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接