ChatGPT解决这个技术问题 Extra ChatGPT

你如何找出对象的类型(在 Swift 中)?

当试图理解一个程序时,或者在某些极端情况下,找出某个东西是什么类型是很有用的。我知道调试器可以向您显示一些类型信息,并且您通常可以依靠类型推断来避免在这些情况下不指定类型,但我仍然非常希望有类似 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 获得),其中将在某处包含类名。但目前尚不清楚如何自己获取类名。
@David 类似,但并非所有变量都是类实例。此外,这些问题实际上是关于检查类型是否与程序员正在寻找的匹配,而我希望只是找出批发的类型

R
Randika Vishman

斯威夫特 3 版本:

type(of: yourObject)

有趣的事实。这不适用于隐式展开的选项!即var myVar: SomeType!。编译器给出错误“无法将类型 'SomeType!.Type' (aka 'ImplicitlyUnwrappedOptional<SomeType>.Type') 的值转换为预期的参数类型 'AnyClass' (aka 'AnyObject.Type') 编译器建议在键入,但随后程序因某些“EXC_BAD_INSTRUCTION”和其他我无法破译的乱码而崩溃。
事实上,既然 Swift 3 存在,这应该是公认的答案。谢谢杰里米!
如果您正在寻找特定的类型名称,当类型是协议类型时,这可能不适合您。
如果您有一个作为 Any 类型传递的 String,那么 type(of:) 将输出 Any,而不是 String
if type(of: yourObject) == MyObjectClass.self { ... }
R
Randika Vishman

斯威夫特 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!")
    }

这很棒。请注意,如果被镜像的对象是可选类型,那么将其与非可选类型进行比较将失败。 StringOptional(String) 不一样。
正是我在寻找的东西,想知道对象的类型是什么
在将可选类型与非可选类型进行比较时,在这种情况下是否存在一种不会失败的比较类型?
这就是我一直在寻找的。谢谢@Gudbergur。
这很甜!但是,是的,您绝对应该为可选用例添加(即:let anyObject: Any? = "testing"),检查 nil -> 如果不是 nil -> 设为非可选 -> 并继续正常回答此答案
R
Randika Vishman

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

嘿,不知道什么时候改变了,但正如 Alex Pretzlav 指出的那样,行为已经改变了。
是的。从 Swift 3.0 开始,subjectType 不再可用,并且 dynamicType 会导致编译器发出弃用消息。
R
Randika Vishman

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

看起来他们将其更改为为您提供类型而不是实例。
@Jiaaro,我用我认为您在原始问题中寻找的内容更新了我的答案
d
daedalus

如果您只需要检查变量是否属于 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>
}

你答案的第二部分是错误的。带有 as? 条件转换的“if let”语句也与 isKindOfClass 相同,只是还提供了转换成功时的结果。
isMemberOfClass 的等价物是条件 object.dynamicType == ClassName.self
R
Randika Vishman

斯威夫特 3:

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

我认为 is 存在于 before Swift 3...?
R
Randika Vishman

对于 Swift 3.0

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

对于 Swift 2.0 - 2.3

String(<Class-Name>)

这个答案对我来说正确的重要一点是,生成的字符串与类名完全匹配——所以我可以使用它从 NSManagedObject 子类中获取核心数据实体名称。我使用了 Swift3 版本。
E
Esqarrouth

这是我推荐的两种方法:

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 运算符更可取。
对我来说获得对象类型的好解决方案。
I
ICL1901

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

print(type(of: myObjectName))

这是上面@Jérémy Lapointe 答案的副本 (stackoverflow.com/a/40132792/764906)
P
Pranav Kasetti

评论:我不明白@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 作为引用包含类型(在 structenumfinal class 的情况下)或动态类型(在非 final 的情况下classes)。

解释

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

介绍 Self 解决了以下问题:dynamicType 仍然是 Swift 小写关键字规则的一个例外。此更改消除了与 Swift 新标准不同步的特殊情况。自我的意图更短更清晰。它反映了 self,它指的是当前实例。它提供了一种更简单的方式来访问静态成员。随着类型名称变大,可读性会受到影响。 MyExtremelyLargeTypeName.staticMember 难以输入和阅读。使用硬连线类型名称的代码比自动知道其类型的代码更难移植。重命名类型意味着更新代码中的任何 TypeName 引用。使用 self.dynamicType 违背了 Swift 简洁明了的目标,因为它既嘈杂又深奥。请注意,self.dynamicType.classMember 和 TypeName.classMember 在具有非最终成员的类类型中可能不是同义词。


j
josef

如果您收到“始终为真/失败”警告,您可能需要在使用 is 之前强制转换为 Any

(foo as Any) is SomeClass

C
Christian Krueger

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

C
CPD

取决于用例。但是让我们假设你想对你的“变量”类型做一些有用的事情。 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 案例。


A
Avi Cohen
//: 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