How do you find out the type of an object (in Swif

2019-01-01 06:47发布

When trying to understand a program, or in some corner-cases, it's useful to be able to actually find out what type something is. I know the debugger can show you some type information, and you can usually rely on type inference to get away with not specifying the type in those situations, but still, I'd really like to have something like Python's type()

dynamicType (see this question)

Update: this has been changed in a recent version of Swift, obj.dynamicType now gives you a reference to the type and not the instance of the dynamic type.

This one seems the most promising, but so far I haven't been able to find out the actual type

class MyClass {
    var count = 0
}

let mc = MyClass()

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

I also tried using a class reference to instantiate a new object, which does work, but oddly gave me an error saying I must add a required initializer:

works:

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

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

Still only a small step toward actually discovering the type of any given object though

edit: I've removed a substantial number of now irrelevant details - look at the edit history if you're interested :)

11条回答
其实,你不懂
2楼-- · 2019-01-01 07:10

Depends on the use case. But let's assume you want to do something useful with your "variable" types. The Swift switch statement is very powerful and can help you get the results you're looking for...

    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
    }

In this case, have a simple dictionary that contains key/value pairs that can be UInt, Int or String. In the .filter() method on the dictionary, I need to make sure I test for the values correctly and only test for a String when it's a string, etc. The switch statement makes this simple and safe! By assigning 9 to the variable of type Any, it makes the switch for Int execute. Try changing it to:

   let eValue:Any = "home9"

..and try it again. This time it executes the as String case.

查看更多
零度萤火
3楼-- · 2019-01-01 07:13

In Swift 2.0 the proper way to do this kind of type introspection would be with the 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)

Then to access the type itself from the Mirror struct you would use the property subjectType like so:

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

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

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

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

You can then use something like this:

    if anyMirror.subjectType == String.self {
        print("anyObject is a string!")
    } else {
        print("anyObject is not a string!")
    }
查看更多
像晚风撩人
4楼-- · 2019-01-01 07:14

For Swift 3.0

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

For Swift 2.0 - 2.3

String(<Class-Name>)
查看更多
像晚风撩人
5楼-- · 2019-01-01 07:18

As of Xcode 6.0.1 (at least, not sure when they added it), your original example now works:

class MyClass {
    var count = 0
}

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

Update:

To answer the original question, you can actually use the Obj-C runtime with plain Swift objects successfully.

Try the following:

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))
查看更多
姐姐魅力值爆表
6楼-- · 2019-01-01 07:22

The "dynamicType.printClassName" code is from an example in the Swift book. There's no way I know of to directly grab a custom class name, but you can check an instances type using the "is" keyword as shown below. This example also shows how to implement a custom className function, if you really want the class name as a string.

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

Note that subclasses of NSObject already implement their own className function. If you're working with Cocoa, you can just use this property.

class MyObj: NSObject {
    init() {
        super.init()
        println("My class is \(self.className)")
    }
}
MyObj()
查看更多
登录 后发表回答