当试图理解一个程序时,或者在某些极端情况下,找出某个东西是什么类型是很有用的。我知道调试器可以向您显示一些类型信息,并且您通常可以依靠类型推断来避免在这些情况下不指定类型,但我仍然非常希望有类似 Python 的 type()
动态类型(见这个问题)
更新:最近版本的 Swift 对此进行了更改,obj.dynamicType
现在为您提供类型的引用,而不是动态类型的实例。
这个似乎最有希望,但到目前为止我还没有找到实际的类型。
class MyClass {
var count = 0
}
let mc = MyClass()
# update: this now evaluates as true
mc.dynamicType === MyClass.self
我还尝试使用类引用来实例化一个新对象,确实工作,但奇怪的是给了我一个错误,说我必须添加一个 required
初始化程序:
作品:
class MyClass {
var count = 0
required init() {
}
}
let myClass2 = MyClass.self
let mc2 = MyClass2()
仍然只有一小步才能真正发现任何给定对象的类型
编辑:我已经删除了大量现在不相关的细节 - 如果您有兴趣,请查看编辑历史:)
print(mc)
或 dump(mc)
将打印一个摘要(您可以从 toString(mc)
或 reflect(mc).summary
获得),其中将在某处包含类名。但目前尚不清楚如何自己获取类名。
斯威夫特 3 版本:
type(of: yourObject)
斯威夫特 2.0:
进行这种类型自省的正确方法是使用 Mirror struct,
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)
然后,要从 Mirror
结构访问类型本身,您将使用属性 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!")
}
String
和 Optional(String)
不一样。
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()
subjectType
不再可用,并且 dynamicType
会导致编译器发出弃用消息。
从 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>
}
as?
条件转换的“if let”语句也与 isKindOfClass
相同,只是还提供了转换成功时的结果。
isMemberOfClass
的等价物是条件 object.dynamicType == ClassName.self
。
斯威夫特 3:
if unknownType is MyClass {
//unknownType is of class type MyClass
}
is
存在于 before Swift 3...?
对于 Swift 3.0
String(describing: <Class-Name>.self)
对于 Swift 2.0 - 2.3
String(<Class-Name>)
这是我推荐的两种方法:
if let thisShape = aShape as? Square
或者:
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")
}
print( aShape is Square )
、is
运算符更可取。
老问题,但这适合我的需要(Swift 5.x):
print(type(of: myObjectName))
评论:我不明白@JérémyLapointe 如何回答这个问题。即使实际类型是更具体的子类,使用 type(of:)
也只能检查编译时信息。现在有一种更简单的方法可以在 Swift 5.1 中动态查询类型,而无需像 @Dash 建议的那样使用 dynamicType
。有关我从何处获得此信息的更多详细信息,请参阅 SE-0068: Expanding Swift Self to class members and value types。
代码
斯威夫特 5.1
// Within an instance method context
Self.self
// Within a static method context
self
这允许使用 Self
作为引用包含类型(在 struct
、enum
和 final class
的情况下)或动态类型(在非 final
的情况下class
es)。
解释
该提案很好地解释了为什么这种方法在 dynamicType
上有所改进:
介绍 Self 解决了以下问题:dynamicType 仍然是 Swift 小写关键字规则的一个例外。此更改消除了与 Swift 新标准不同步的特殊情况。自我的意图更短更清晰。它反映了 self,它指的是当前实例。它提供了一种更简单的方式来访问静态成员。随着类型名称变大,可读性会受到影响。 MyExtremelyLargeTypeName.staticMember 难以输入和阅读。使用硬连线类型名称的代码比自动知道其类型的代码更难移植。重命名类型意味着更新代码中的任何 TypeName 引用。使用 self.dynamicType 违背了 Swift 简洁明了的目标,因为它既嘈杂又深奥。请注意,self.dynamicType.classMember 和 TypeName.classMember 在具有非最终成员的类类型中可能不是同义词。
如果您收到“始终为真/失败”警告,您可能需要在使用 is
之前强制转换为 Any
(foo as Any) is SomeClass
如果将参数作为 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 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
案例。
//: 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
var myVar: SomeType!
。编译器给出错误“无法将类型 'SomeType!.Type' (aka 'ImplicitlyUnwrappedOptional<SomeType>.Type') 的值转换为预期的参数类型 'AnyClass' (aka 'AnyObject.Type') 编译器建议在键入,但随后程序因某些“EXC_BAD_INSTRUCTION”和其他我无法破译的乱码而崩溃。Any
类型传递的String
,那么type(of:)
将输出Any
,而不是String
。