How do you find out the type of an object (in Swift)?

IosSwiftTypechecking

Ios Problem Overview


When trying to understand a program, or in some corner-cases, it's useful to 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 I haven't been able to find out the actual type so far.

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

Ios Solutions


Solution 1 - Ios

Swift 3 version:

type(of: yourObject)

Solution 2 - Ios

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

Solution 3 - Ios

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

Solution 4 - Ios

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

Solution 5 - Ios

If you simply need to check whether the variable is of type X, or that it conforms to some protocol, then you can use is, or as? as in the following:

var unknownTypeVariable = …

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

This is equivalent of isKindOfClass in Obj-C.

And this is equivalent of conformsToProtocol, or 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>
}

Solution 6 - Ios

Swift 3:

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

Solution 7 - Ios

For Swift 3.0

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

For Swift 2.0 - 2.3

String(<Class-Name>)

Solution 8 - Ios

Here is 2 ways I recommend doing it:

if let thisShape = aShape as? Square 

Or:

aShape.isKindOfClass(Square)

Here is a detailed example:

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

Solution 9 - Ios

Old question, but this works for my need (Swift 5.x):

print(type(of: myObjectName))

Solution 10 - Ios

Comment: I don't see how @JérémyLapointe answers the question. Using type(of:) only works by checking the compile-time information even if the actual type is a more specific subclass. There is now an easier way to dynamically query the type in Swift 5.1 without resorting to dynamicType like @Dash suggests. For more details on where I got this information, see SE-0068: Expanding Swift Self to class members and value types.


Code

Swift 5.1

// Within an instance method context
Self.self

// Within a static method context
self

This allows the use of Self as shorthand for referring to the containing type (in the case of structs, enums, and final class) or the dynamic type (in the case of non-final classes).

Explanation

The proposal explains well why this approach improves on dynamicType:

> Introducing Self addresses the following issues: > > - dynamicType remains an exception to Swift's lowercased keywords rule. This change eliminates a special case that's out of step with > Swift's new standards. Self is shorter and clearer in its intent. It > mirrors self, which refers to the current instance. > - It provides an easier way to access static members. As type names grow large, readability suffers. > MyExtremelyLargeTypeName.staticMember is unwieldy to type and read. > - Code using hardwired type names is less portable than code that automatically knows its type. > - Renaming a type means updating any TypeName references in code. Using self.dynamicType fights against Swift's goals of concision and > clarity in that it is both noisy and esoteric. > > Note that self.dynamicType.classMember and TypeName.classMember > may not be synonyms in class types with non-final members.

Solution 11 - Ios

If you get an "always true/fails" warning you may need to cast to Any before using is

(foo as Any) is SomeClass

Solution 12 - Ios

If a parameter is passed as Any to your function, you can test on a special type like so :

   func isADate ( aValue : Any?) -> Bool{
        if (aValue as? Date) != nil {
            print ("a Date")
            return true
        }
        else {
            print ("This is not a date ")
            return false
        }
    }

Solution 13 - Ios

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.

Solution 14 - Ios

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJiaaroView Question on Stackoverflow
Solution 1 - IosJérémy LapointeView Answer on Stackoverflow
Solution 2 - IosGudbergurView Answer on Stackoverflow
Solution 3 - IosDashView Answer on Stackoverflow
Solution 4 - IosAlex PretzlavView Answer on Stackoverflow
Solution 5 - IosValerii LiderView Answer on Stackoverflow
Solution 6 - IosPeterView Answer on Stackoverflow
Solution 7 - IostechloverrView Answer on Stackoverflow
Solution 8 - IosEsqarrouthView Answer on Stackoverflow
Solution 9 - IosICL1901View Answer on Stackoverflow
Solution 10 - IosPranav KasettiView Answer on Stackoverflow
Solution 11 - IosjosefView Answer on Stackoverflow
Solution 12 - IosChristian KruegerView Answer on Stackoverflow
Solution 13 - IosCPDView Answer on Stackoverflow
Solution 14 - IosAvi CohenView Answer on Stackoverflow