在试图理解一个程序时,或者在某些极端情况下,找出某个东西的类型是很有用的。我知道调试器可以向您显示一些类型信息,在这些情况下,您通常可以依靠类型推断来避免不指定类型,但我仍然希望有类似Python的type()的东西。

dynamicType(参见这个问题)

更新:在Swift的最新版本中,obj已被更改。dynamicType现在提供了对类型的引用,而不是动态类型的实例。

这款似乎最有希望,但到目前为止我还没能找到实际的型号。

class MyClass {
    var count = 0
}

let mc = MyClass()

# update: this now evaluates as true
mc.dynamicType === MyClass.self

我还尝试使用类引用来实例化一个新对象,这确实有效,但奇怪的是,给了我一个错误,说我必须添加一个必需的初始化器:

工作原理:

class MyClass {
    var count = 0
    required init() {
    }
}

let myClass2 = MyClass.self
let mc2 = MyClass2()

不过,要真正发现任何给定对象的类型,这仍然只是一小步

编辑:我已经删除了大量现在不相关的细节-如果你感兴趣,看看编辑历史:)


dynamicType。printClassName代码来自Swift书籍中的一个示例。我不知道如何直接获取自定义类名,但可以使用is关键字检查实例类型,如下所示。这个例子还展示了如何实现一个自定义的className函数,如果你真的想要类名作为字符串。

class Shape {
    class func className() -> String {
        return "Shape"
    }
}

class Square: Shape {
    override class func className() -> String {
        return "Square"
    }
}

class Circle: Shape {
    override class func className() -> String {
        return "Circle"
    }
}

func getShape() -> Shape {
    return Square() // hardcoded for example
}

let newShape: Shape = getShape()
newShape is Square // true
newShape is Circle // false
newShape.dynamicType.className() // "Square"
newShape.dynamicType.className() == Square.className() // true

注意:NSObject的子类已经实现了他们自己的className函数。如果您正在使用Cocoa,您可以使用这个属性。

class MyObj: NSObject {
    init() {
        super.init()
        println("My class is \(self.className)")
    }
}
MyObj()

从Xcode 6.0.1开始(至少,不确定他们什么时候添加的),你原来的例子现在可以工作了:

class MyClass {
    var count = 0
}

let mc = MyClass()
mc.dynamicType === MyClass.self // returns `true`

更新:

要回答最初的问题,您实际上可以成功地将Objective-C运行时与普通Swift对象一起使用。

试试下面的方法:

import Foundation
class MyClass { }
class SubClass: MyClass { }

let mc = MyClass()
let m2 = SubClass()

// Both of these return .Some("__lldb_expr_35.SubClass"), which is the fully mangled class name from the playground
String.fromCString(class_getName(m2.dynamicType))
String.fromCString(object_getClassName(m2))
// Returns .Some("__lldb_expr_42.MyClass")
String.fromCString(object_getClassName(mc))

如果您只是需要检查变量是否属于X类型,或者它是否符合某种协议,那么您可以使用is或as?具体如下:

var unknownTypeVariable = …

if unknownTypeVariable is <ClassName> {
    //the variable is of type <ClassName>
} else {
    //variable is not of type <ClassName>
}

这相当于Obj-C中的isKindOfClass。

这等价于conformsToProtocol或isMemberOfClass

var unknownTypeVariable = …

if let myClass = unknownTypeVariable as? <ClassName or ProtocolName> {
    //unknownTypeVarible is of type <ClassName or ProtocolName>
} else {
    //unknownTypeVariable is not of type <ClassName or ProtocolName>
}

以下是我推荐的两种方法:

if let thisShape = aShape as? Square 

Or:

aShape.isKindOfClass(Square)

下面是一个详细的例子:

class Shape { }
class Square: Shape { } 
class Circle: Shape { }

var aShape = Shape()
aShape = Square()

if let thisShape = aShape as? Square {
    println("Its a square")
} else {
    println("Its not a square")
}

if aShape.isKindOfClass(Square) {
    println("Its a square")
} else {
    println("Its not a square")
}

斯威夫特2.0:

进行这种类型内省的正确方法是使用Mirror结构体,

    let stringObject:String = "testing"
    let stringArrayObject:[String] = ["one", "two"]
    let viewObject = UIView()
    let anyObject:Any = "testing"

    let stringMirror = Mirror(reflecting: stringObject)
    let stringArrayMirror = Mirror(reflecting: stringArrayObject)
    let viewMirror = Mirror(reflecting: viewObject)
    let anyMirror = Mirror(reflecting: anyObject)

然后要从镜像结构体中访问类型本身,你可以像这样使用属性subjectType:

    // Prints "String"
    print(stringMirror.subjectType)

    // Prints "Array<String>"
    print(stringArrayMirror.subjectType)

    // Prints "UIView"
    print(viewMirror.subjectType)

    // Prints "String"
    print(anyMirror.subjectType)

然后你可以这样使用:

    if anyMirror.subjectType == String.self {
        print("anyObject is a string!")
    } else {
        print("anyObject is not a string!")
    }

这取决于用例。但是让我们假设您想要对“变量”类型做一些有用的事情。Swift switch语句非常强大,可以帮助你得到你想要的结果…

    let dd2 = ["x" : 9, "y" : "home9"]
    let dds = dd2.filter {
        let eIndex = "x"
        let eValue:Any = 9
        var r = false

        switch eValue {
        case let testString as String:
            r = $1 == testString
        case let testUInt as UInt:
            r = $1 == testUInt
        case let testInt as Int:
            r = $1 == testInt
        default:
            r = false
        }

        return r && $0 == eIndex
    }

在这种情况下,有一个简单的字典,其中包含键/值对,可以是UInt, Int或String。在字典上的.filter()方法中,我需要确保正确地测试值,并且只在字符串时测试字符串,等等。switch语句使此操作简单而安全! 通过将9赋值给Any类型的变量,它将执行Int类型的转换。试着把它改成:

   let eValue:Any = "home9"

..再试一次。这一次,它执行了as String的情况。

如果你得到一个“总是真/失败”的警告,你可能需要在使用is之前强制转换为Any

(foo as Any) is SomeClass
//: Playground - noun: a place where people can play

import UIKit

class A {
    class func a() {
        print("yeah")
    }

    func getInnerValue() {
        self.dynamicType.a()
    }
}

class B: A {
    override class func a() {
        print("yeah yeah")
    }
}

B.a() // yeah yeah
A.a() // yeah
B().getInnerValue() // yeah yeah
A().getInnerValue() // yeah

Swift 3版本:

type(of: yourObject)

针对Swift 3.0

String(describing: <Class-Name>.self)

Swift 2.0 - 2.3

String(<Class-Name>)

斯威夫特3:

if unknownType is MyClass {
   //unknownType is of class type MyClass
}

如果一个参数作为Any传递给你的函数,你可以测试一个特殊的类型,像这样:

   func isADate ( aValue : Any?) -> Bool{
        if (aValue as? Date) != nil {
            print ("a Date")
            return true
        }
        else {
            print ("This is not a date ")
            return false
        }
    }

老问题,但这符合我的需要(Swift 5.x):

print(type(of: myObjectName))

评论:我不明白@JérémyLapointe如何回答这个问题。使用type(of:)只能通过检查编译时信息来工作,即使实际类型是一个更特定的子类。现在在Swift 5.1中有一个更简单的方法来动态查询类型,而不需要像@Dash建议的那样诉诸dynamicType。有关我从哪里得到这些信息的更多详细信息,请参阅SE-0068:将Swift Self扩展到类成员和值类型。


Code

斯威夫特5.1

// Within an instance method context
Self.self

// Within a static method context
self

这允许使用Self作为引用包含类型(在结构、枚举和final类的情况下)或动态类型(在非final类的情况下)的简写。

解释

提案很好地解释了为什么这种方法改进了dynamicType:

Introducing Self addresses the following issues: dynamicType remains an exception to Swift's lowercased keywords rule. This change eliminates a special case that's out of step with Swift's new standards. Self is shorter and clearer in its intent. It mirrors self, which refers to the current instance. It provides an easier way to access static members. As type names grow large, readability suffers. MyExtremelyLargeTypeName.staticMember is unwieldy to type and read. Code using hardwired type names is less portable than code that automatically knows its type. Renaming a type means updating any TypeName references in code. Using self.dynamicType fights against Swift's goals of concision and clarity in that it is both noisy and esoteric. Note that self.dynamicType.classMember and TypeName.classMember may not be synonyms in class types with non-final members.