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


当前回答

影响从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替换或正则表达式函数。

这只是我的个人意见。

其他回答

在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中获得对象类型或对象类,您必须使用类型(of: youobject)

类型(:yourObject)

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

在lldb beta 5中,你可以通过以下命令查看对象的类:

fr v -d r shipDate

输出如下:

(DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940

展开的命令是这样的:

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

需要知道的一点是,使用“Frame Variable”来输出变量值可以确保不执行任何代码。

您仍然可以通过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'

如果你想获取一个原语的类型,你必须使用bridgetooobjecvec()。例子:

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