你如何找到一个对象的类型(在Swift中)?

时间:2014-06-07 20:46:23

标签: swift typechecking

当试图理解程序时,或者在某些角落情况下,能够真正找出某些类型的东西是有用的。我知道调试器可以显示一些类型信息,你通常可以依靠类型推断来避免在那些情况下没有指定类型,但是,我仍然希望得到类似Python的type() < / p>

dynamicType(参见this question

更新:在最新版本的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()

通过

实际发现任何给定对象的类型仍然只是一小步

修改:我删除了大量现在不相关的详细信息 - 如果您有兴趣,请查看修改历史记录:)

14 个答案:

答案 0 :(得分:239)

Swift 3版本:

type(of: yourObject)

答案 1 :(得分:106)

Swift 2.0:

进行这种类型内省的正确方法是使用Mirror struct

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

然后你可以使用这样的东西:

wrap_content

答案 2 :(得分:58)

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

答案 3 :(得分:41)

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

答案 4 :(得分:35)

如果您只是需要检查变量是否为X类型,或者它是否符合某些协议,那么您可以使用isas?,如下所示:

var unknownTypeVariable = …

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

这相当于Obj-C中的isKindOfClass

这相当于conformsToProtocolisMemberOfClass

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

答案 5 :(得分:15)

斯威夫特3:

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

答案 6 :(得分:8)

我建议采用以下两种方式:

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

答案 7 :(得分:6)

适用于Swift 3.0

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

适用于Swift 2.0 - 2.3

String(<Class-Name>)

答案 8 :(得分:2)

评论:我不明白@JérémyLapointe 如何回答这个问题。使用 type(of:) 只能通过检查编译时信息来工作,即使实际类型是更具体的子类。现在有一种更简单的方法可以在 Swift 5.1 中动态查询类型,而无需像 @Dash 建议的那样求助于 dynamicType。有关我从何处获得此信息的更多详细信息,请参阅 SE-0068: Expanding Swift Self to class members and value types


代码

Swift 5.1

// Within an instance method context
Self.self

// Within a static method context
self

这允许使用 Self 作为引用包含类型的简写(在 structs、enums 和 final class 的情况下)或动态类型(在非final classes 的情况下)。

说明

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

<块引用>

引入 Self 解决了以下问题:

  • dynamicType 仍然是 Swift 的小写关键字规则的一个例外。此更改消除了与不同步的特殊情况 Swift 的新标准。 Self 的意图更短更清晰。它 镜像 self,指的是当前实例。
  • 它提供了一种更简单的方式来访问静态成员。随着类型名称变大,可读性受到影响。 MyExtremelyLargeTypeName.staticMember 难以打字和阅读。
  • 使用硬连线类型名称的代码的可移植性低于自动知道其类型的代码。
  • 重命名类型意味着更新代码中的任何 TypeName 引用。使用 self.dynamicType 与 Swift 的简洁目标和 清晰,因为它既嘈杂又深奥。

注意 self.dynamicType.classMemberTypeName.classMember 可能不是具有非 final 成员的类类型中的同义词。

答案 9 :(得分:1)

取决于用例。但是,让我们假设你想对你的&#34;变量&#34;做一些有用的事情。类型。 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()方法中,我需要确保正确地测试值,并且仅当字符串为字符串时才测试字符串等.top语句使这简单而安全! 通过将9分配给Any类型的变量,它使得Int的开关执行。尝试将其更改为:

   let eValue:Any = "home9"

..再试一次。这次它执行as String案例。

答案 10 :(得分:1)

旧问题,但这可以满足我的需要(Swift 5.x):

print(type(of: myObjectName))

答案 11 :(得分:0)

如果您收到“始终为真/失败”警告,则可能需要在使用is

之前强制转换为Any
(foo as Any) is SomeClass

答案 12 :(得分:0)

//: 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

答案 13 :(得分:0)

如果将参数作为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
        }
    }