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

Jia*_*aro 242 typechecking swift

当试图理解程序时,或者在某些角落情况下,能够真正找出什么类型的东西是有用的.我知道调试器可以显示一些类型信息,你通常可以依赖类型推断来避免在那些情况下不指定类型,但是,我仍然喜欢像Python这样的东西type()

dynamicType(查看此问题)

更新:这在最近的Swift版本中已经更改,obj.dynamicType现在为您提供类型的引用,而不是动态类型的实例.

这个似乎是最有希望的,但到目前为止我还没有找到实际的类型

class MyClass {
    var count = 0
}

let mc = MyClass()

# update: this now evaluates as true
mc.dynamicType === MyClass.self
Run Code Online (Sandbox Code Playgroud)

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

作品:

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

let myClass2 = MyClass.self
let mc2 = MyClass2()
Run Code Online (Sandbox Code Playgroud)

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

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

Jér*_*nte 255

Swift 3版本:

type(of: yourObject)
Run Code Online (Sandbox Code Playgroud)

  • 有趣的事实.这不适用于隐式解包的选项!即`var myVar:SomeType!`.编译器给出错误"无法将类型'SomeType!.Type'(又名'ImplicitlyUnwrappedOptional <SomeType> .Type')的值转换为预期的参数类型'AnyClass'(又名'AnyObject.Type')编译器建议添加`as!AnyClass`在类型之后,然后程序崩溃了一些"EXC_BAD_INSTRUCTION"和其他jiberrish我无法破译. (7认同)
  • 如果你有一个以`Any`类型传递的`String`,那么`type(of:)`将输出`Any`,而不是`String`。 (2认同)
  • if type(of: yourObject) == MyObjectClass.self { ... } (2认同)

小智 107

在Swift 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)
Run Code Online (Sandbox Code Playgroud)

然后从Mirror结构中访问类型本身,您将使用属性,subjectType如下所示:

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

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

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

    // Prints "String"
    print(anyMirror.subjectType)
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这很棒.请注意,如果要镜像的对象是可选类型,则将其与非可选类型进行比较将失败.`String`和`Optional(String)`不一样. (7认同)

Das*_*ash 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
Run Code Online (Sandbox Code Playgroud)

请注意,NSObject的子类已经实现了自己的className函数.如果你正在使用Cocoa,你可以使用这个属性.

class MyObj: NSObject {
    init() {
        super.init()
        println("My class is \(self.className)")
    }
}
MyObj()
Run Code Online (Sandbox Code Playgroud)

  • 嘿,不知道什么时候改变了,但正如Alex Pretzlav指出的那样,行为发生了变化. (2认同)

Ale*_*lav 41

从Xcode 6.0.1开始(至少,不确定何时添加它),您的原始示例现在可以正常工作:

class MyClass {
    var count = 0
}

let mc = MyClass()
mc.dynamicType === MyClass.self // returns `true`
Run Code Online (Sandbox Code Playgroud)

更新:

要回答原始问题,您实际上可以成功使用Obj-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))
Run Code Online (Sandbox Code Playgroud)


Val*_*der 36

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

var unknownTypeVariable = …

if unknownTypeVariable is <ClassName> {
    //the variable is of type <ClassName>
} else {
    //variable is not of type <ClassName>
}
Run Code Online (Sandbox Code Playgroud)

这相当于isKindOfClassObj-C.

这相当于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>
}
Run Code Online (Sandbox Code Playgroud)


小智 16

这适用于swift 3

if unknownType is MyClass {
   //unknownType is of class type MyClass
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*nte 10

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

print(type(of: myObjectName))
Run Code Online (Sandbox Code Playgroud)


tec*_*err 9

对于Swift 3.0

String(describing: <Class-Name>.self)
Run Code Online (Sandbox Code Playgroud)

对于Swift 2.0 - 2.3

String(<Class-Name>)
Run Code Online (Sandbox Code Playgroud)


Esq*_*uth 8

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

if let thisShape = aShape as? Square 
Run Code Online (Sandbox Code Playgroud)

要么:

aShape.isKindOfClass(Square)
Run Code Online (Sandbox Code Playgroud)

这是一个详细的例子:

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")
}
Run Code Online (Sandbox Code Playgroud)

  • `print(aShape is Square)`,`is`运算符更为可取. (2认同)

Pra*_*tti 7

评论:我不明白@J\xc3\xa9r\xc3\xa9myLapointe 如何回答这个问题。type(of:)即使实际类型是更具体的子类,仅通过检查编译时信息即可使用。现在有一种更简单的方法可以动态查询Swift 5.1中的类型,而无需像 @Dash 建议那样求助dynamicType。有关我从何处获得此信息的更多详细信息,请参阅SE-0068:将 Swift Self 扩展到类成员和值类型

\n
\n

代码

\n

斯威夫特 5.1

\n
// Within an instance method context\nSelf.self\n\n// Within a static method context\nself\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

解释

\n

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

\n
\n

引入Self解决了以下问题:

\n
    \n
  • dynamicType仍然是 Swift 小写关键字规则的例外。此更改消除了与 Swift 新标准不一致的特殊情况。Self 的含义更短、更清晰。It\nmirrors self,指的是当前实例。
  • \n
  • 它提供了一种更简单的方法来访问静态成员。随着类型名称变大,可读性会受到影响。\nMyExtremelyLargeTypeName.staticMember难以键入和读取。
  • \n
  • 使用硬连线类型名称的代码比自动知道其类型的代码的可移植性较差。
  • \n
  • 重命名类型意味着更新TypeName代码中的任何引用。与 Swift 简洁明晰的目标相悖self.dynamicType,因为它既嘈杂又深奥。
  • \n
\n

请注意,self.dynamicType.classMemberand TypeName.classMember\n在具有非最终成员的类类型中可能不是同义词。

\n
\n