Get class name of object as string in Swift

20 Solutions Collect From Internet About “Get class name of object as string in Swift”

String from an instance, e.g. myViewController:

String(describing: type(of: myViewController))

String from a type, e.g. MyViewController:

String(describing: MyViewController.self)

Edit: Updated for Swift 3, thanks @AmitaiB

UPDATED TO SWIFT 3

We can get pretty descriptions of type names using the instance variable through the String initializer and create new objects of a certain class

Like, for example print(String(describing: type(of: object))). Where object can be an instance variable like array, a dictionary, an Int, a NSDate, etc.

Because NSObject is the root class of most Objective-C class hierarchies, you coud try to make an extension for NSObject to get the class name of every subclass of NSObject. Like this:

extension NSObject {
    var theClassName: String {
        return NSStringFromClass(type(of: self))
    }
}

Or you could make a static funcion whose parameter is of type Any (The protocol to which all types implicitly conform) and returns the class name as String. Like this:

class Utility{
    class func classNameAsString(obj: Any) -> String {
        //prints more readable results for dictionaries, arrays, Int, etc
        return String(describing: type(of: obj))
    }
} 

Now you can do something like this:

class ClassOne : UIViewController{ // some code here }
class ClassTwo : ClassOne{ // some code here }

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Get the class name as String
        let dictionary: [String: CGFloat] = [:]
        let array: [Int] = []
        let int = 9
        let numFloat: CGFloat = 3.0
        let numDouble: Double = 1.0
        let classOne = ClassOne()
        let classTwo: ClassTwo? = ClassTwo()
        let now = NSDate()
        let lbl = UILabel()

        print("diccionary: [String: CGFloat] = [:] -> \(Utility.classNameAsString(diccionary))")
        print("array: [Int] = [] -> \(Utility.classNameAsString(array))")
        print("int = 9 -> \(Utility.classNameAsString(int))")
        print("numFloat: CGFloat = 3.0 -> \(Utility.classNameAsString(numFloat))")
        print("numDouble: Double = 1.0 -> \(Utility.classNameAsString(numDouble))")
        print("classOne = ClassOne() -> \((ClassTwo?).self)") //we use the Extension
        if classTwo != nil {
            print("classTwo: ClassTwo? = ClassTwo() -> \(Utility.classNameAsString(classTwo!))") //now we can use a Forced-Value Expression and unwrap the value
        }
        print("now = Date() -> \(Utility.classNameAsString(now))")
        print("lbl = UILabel() -> \(String(describing: type(of: lbl)))") // we use the String initializer directly

    }
}

Also, once we can get the class name as String, we can instanciate new objects of that class:

// Instanciate a class from a String
print("\nInstaciate a class from a String")
let aClassName = classOne.theClassName
let aClassType = NSClassFromString(aClassName) as! NSObject.Type
let instance = aClassType.init() // we create a new object
print(String(cString: class_getName(type(of: instance))))
print(instance.self is ClassOne)

Maybe this helps someone out there!.

Swift 3.1

Here is the extension to get the className as a variable (for both instance or class object).

extension NSObject {
    var className: String {
        return String(describing: type(of: self))
    }

    class var className: String {
        return String(describing: self)
    }
}

How to use:

print(self.className)
print(ViewController.className)

Swift 3.0

String(describing: MyViewController.self)

I suggest such an approach (very Swifty):

// Swift 3
func typeName(_ some: Any) -> String {
    return (some is Any.Type) ? "\(some)" : "\(type(of: some))"
}

// Swift 2
func typeName(some: Any) -> String {
    return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)"
}

It doesn’t use neither introspection nor manual demangling (no magic!).


Here is a demo:

// Swift 3

import class Foundation.NSObject

func typeName(_ some: Any) -> String {
    return (some is Any.Type) ? "\(some)" : "\(type(of: some))"
}

class GenericClass<T> {
    var x: T? = nil
}

protocol Proto1 {
    func f(x: Int) -> Int
}


@objc(ObjCClass1)
class Class1: NSObject, Proto1 {
    func f(x: Int) -> Int {
        return x
    }
}

struct Struct1 {
    var x: Int
}

enum Enum1 {
    case X
}

print(typeName(GenericClass<Int>.self)) // GenericClass<Int>
print(typeName(GenericClass<Int>()))  // GenericClass<Int>

print(typeName(Proto1.self)) // Proto1

print(typeName(Class1.self))   // Class1
print(typeName(Class1())) // Class1
print(typeName(Class1().f)) // (Int) -> Int

print(typeName(Struct1.self)) // Struct1
print(typeName(Struct1(x: 1))) // Struct1
print(typeName(Enum1.self)) // Enum1
print(typeName(Enum1.X)) // Enum1

If you have type Foo, the following code will give you "Foo" in Swift 3 and Swift 4:

let className = String(describing: Foo.self) // Gives you "Foo"

The problem with most of the answers on here are that they give you "Foo.Type" as the resulting string when you don’t have any instance of the type, when what you really want is just "Foo". The following gives you "Foo.Type", as mentioned in a bunch of the other answers.

let className = String(describing: type(of: Foo.self)) // Gives you "Foo.Type"

The type(of:) part is unnecessary if you just want "Foo".

You can use the Swift standard library function called _stdlib_getDemangledTypeName like this:

let name = _stdlib_getDemangledTypeName(myViewController)

One can also use mirrors:

let vc = UIViewController()

String(Mirror(reflecting: vc).subjectType)

NB: This method can also be used for Structs and Enums. There is a displayStyle that gives an indication of what type of the structure:

Mirror(reflecting: vc).displayStyle

The return is an enum so you can:

Mirror(reflecting: vc).displayStyle == .Class

you can try this way:

 self.classForCoder.description()

Swift 3.0:
You can create an extension like this one.. It gives back the class name without the project name

extension NSObject {
    var className: String {
        return NSStringFromClass(self as! AnyClass).components(separatedBy: ".").last ?? ""
    }

    public class var className: String {
        return NSStringFromClass(self).components(separatedBy: ".").last ?? ""
    }
}

To get the type name as a string in Swift 4 (I haven’t checked the earlier versions), just use string interpolation:

"\(type(of: myViewController))"

You can use .self on a type itself, and the type(of:_) function on an instance:

// Both constants will have "UIViewController" as their value
let stringFromType = "\(UIViewController.self)"
let stringFromInstance = "\(type(of: UIViewController()))"

I’ve been looking for this answer off and on for a while. I use GKStateMachine and like to observe state changes and wanted an easy way to see just the class name. I’m not sure if it’s just iOS 10 or Swift 2.3, but in that environment, the following does exactly what I want:

let state:GKState?
print("Class Name: \(String(state.classForCoder)")

// Output:    
// Class Name: GKState

Try reflect().summary on Class self or instance dynamicType. Unwrap optionals before getting dynamicType otherwise the dynamicType is the Optional wrapper.

class SampleClass { class InnerClass{} }
let sampleClassName = reflect(SampleClass.self).summary;
let instance = SampleClass();
let instanceClassName = reflect(instance.dynamicType).summary;
let innerInstance = SampleClass.InnerClass();
let InnerInstanceClassName = reflect(innerInstance.dynamicType).summary.pathExtension;
let tupleArray = [(Int,[String:Int])]();
let tupleArrayTypeName = reflect(tupleArray.dynamicType).summary;

The summary is a class path with generic types described. To get a simple class name from the summary try this method.

func simpleClassName( complexClassName:String ) -> String {
    var result = complexClassName;
    var range = result.rangeOfString( "<" );
    if ( nil != range ) { result = result.substringToIndex( range!.startIndex ); }
    range = result.rangeOfString( "." );
    if ( nil != range ) { result = result.pathExtension; }
    return result;
}

Swift 3.0 (macOS 10.10 and later), you can get it from className

self.className.components(separatedBy: ".").last!

I tried type(of:...) in Playground with Swift 3. This is my result.
This is the code format version.

print(String(describing: type(of: UIButton.self)))
print(String(describing: type(of: UIButton())))
UIButton.Type
UIButton

To get class name as String declare your class as following

@objc(YourClassName) class YourClassName{}

And get class name using following syntax

NSStringFromClass(YourClassName)

I use it in Swift 2.2

guard let currentController = UIApplication.topViewController() else { return }
currentController.classForCoder.description().componentsSeparatedByString(".").last!

Sometimes the other solutions will give a non useful name depending on what object you are trying to look at. In that case you can get the class name as a string using the following.

String(cString: object_getClassName(Any!))

⌘ click the function in xcode to see some related methods that are fairly useful. or check here https://developer.apple.com/reference/objectivec/objective_c_functions

The above solutions didn’t work for me. The produced mostly the issues mention in several comments:

MyAppName.ClassName

or

MyFrameWorkName.ClassName

This solutions worked on XCode 9, Swift 3.0:

I named it classNameCleaned so it is easier to access and doesn’t conflict with future className() changes:

extension NSObject {

static var classNameCleaned : String {

    let className = self.className()
    if className.contains(".") {
        let namesArray = className.components(separatedBy: ".")
        return namesArray.last ?? className
    } else {
        return self.className()
    }

}

}

Usage:

NSViewController.classNameCleaned
MyCustomClass.classNameCleaned

If you don’t like the mangled name, you can dictate your own name:

@objc(CalendarViewController) class CalendarViewController : UIViewController {
    // ...
}

However, it would be better in the long run to learn to parse the mangled name. The format is standard and meaningful and won’t change.