428

Getting the classname of an object as String using:

object_getClassName(myViewController)

returns something like this:

_TtC5AppName22CalendarViewController

I am looking for the pure version: "CalendarViewController". How do I get a cleaned up string of the class name instead?

I found some attempts of questions about this but not an actual answer. Is it not possible at all?

Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
Bernd
  • 11,133
  • 11
  • 65
  • 98

32 Answers32

692

String from an instance:

String(describing: self)

String from a type:

String(describing: YourType.self)

Example:

struct Foo {

    // Instance Level
    var typeName: String {
        return String(describing: Foo.self)
    }

    // Instance Level - Alternative Way
    var otherTypeName: String {
        let thisType = type(of: self)
        return String(describing: thisType)
    }

    // Type Level
    static var typeName: String {
        return String(describing: self)
    }

}

Foo().typeName       // = "Foo"
Foo().otherTypeName  // = "Foo"
Foo.typeName         // = "Foo"

Tested with class, struct and enum.

Andrew Sun
  • 4,101
  • 6
  • 36
  • 53
Rudolf Adamkovič
  • 31,030
  • 13
  • 103
  • 118
  • 6
    Is this really the case? According to the docs for String for this initializer "an unspecified result is supplied automatically by the Swift standard library" when it doesn't conform to Streamable, or CustomStringConvertible, or CustomDebugStringConvertible. So while it may be displaying the desired value now, will it continue to do so in the future? – Tod Cunningham Apr 13 '16 at 22:16
  • 4
    Using this in Xcode 7.3.1 & Swift 2.2 produces the following, which is no ideal. ''let name = String(self) name String ""'' – CodeBender Jul 19 '16 at 16:39
  • @CodeBender with a helper function [like this](http://stackoverflow.com/a/34375827/3541063) you wouldn't care whether you have an instance or a type object. – werediver Jul 21 '16 at 16:00
  • In xcode 8/swift 3 I get – Doug Amos Oct 03 '16 at 10:17
  • 14
    In Swift 3, the proper answer is to call `String(describing: MyViewController.self)` as noted in a few answers below. – AmitaiB Oct 09 '16 at 20:07
  • 12
    But it returns "MyViewController.TYPE"! – orkenstein Dec 23 '16 at 02:03
  • @orkenstein I just tried it in a playground. It returns `MyViewController`. – Rudolf Adamkovič Dec 25 '16 at 23:34
  • 1
    I prefer `type(of: self)` instead of `YourType.self` (Alternative Way in the example). – Marián Černý Mar 13 '18 at 20:05
  • 1
    @MariánČerný From what I understand, `type(of:)` is evaluated dynamically at runtime whereas `Type.self` is not. – Rudolf Adamkovič Mar 14 '18 at 16:32
  • 4
    @RudolfAdamkovič Yes, that would be true. But I don't like writing the class name explicitly (what If I rename the class `Foo` to `Foo2` but create a class `Foo` elsewhere, that might brake the code). In case of subclassing you need to use either `type(of:)` or `Type.self` depending what fits your need. Probably `type(of:)` is more appropriate for getting the class name. – Marián Černý Mar 15 '18 at 16:22
  • 2
    "Alternative Way" should be the primary way. – Dmitry May 02 '19 at 06:23
  • For nested types, like `struct Foo { struct Bar {} }` and `struct OtherFoo { struct Bar{} }` we get the same name from `String(describing:Foo.Bar.self)` and `String(describing:OtherFoo.Bar.self)`. In this case, `String(reflecting:Foo.Bar.self)` is a better fit, because it will give us the fully qualified name of the type: `MyApp.Foo.Bar`. – Timothy Davison Oct 09 '20 at 00:55
  • Does it return valid name if there were some obfuscation? – Farid Dec 23 '22 at 16:30
231

UPDATED TO SWIFT 5

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 could 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("dictionary: [String: CGFloat] = [:] -> \(Utility.classNameAsString(dictionary))")
        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() -> \((ClassOne).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 instantiate new objects of that class:

// Instantiate a class from a String
print("\nInstantiate 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!.

jbafford
  • 5,528
  • 1
  • 24
  • 37
mauricioconde
  • 5,032
  • 3
  • 28
  • 24
  • 5
    `classNameAsString` can be simplified to `className`, for that "name" implied its type. `theClassName` is simillar to facebook's story, which is named thefacebook originally. – DawnSong Oct 19 '16 at 05:26
  • "diccionary"...the Italian version of Swift's dictionary collection :] – Andrew Kirna Jun 26 '19 at 21:35
  • This solution prepending projectname for each classTag, i.e. `ProjectTest.MyViewController`. How do I get rid of this project name? I want only class name. – Sazzad Hissain Khan Nov 01 '19 at 07:50
162

Swift 5

Here is the extension to get the typeName as a variable (work with both value type or reference type).

protocol NameDescribable {
    var typeName: String { get }
    static var typeName: String { get }
}

extension NameDescribable {
    var typeName: String {
        return String(describing: type(of: self))
    }

    static var typeName: String {
        return String(describing: self)
    }
}

How to use:

// Extend with class/struct/enum...
extension NSObject: NameDescribable {}
extension Array: NameDescribable {}
extension UIBarStyle: NameDescribable { }

print(UITabBarController().typeName)
print(UINavigationController.typeName)
print([Int]().typeName)
print(UIBarStyle.typeName)

// Out put:
UITabBarController
UINavigationController
Array<Int>
UIBarStyle
nahung89
  • 7,745
  • 3
  • 38
  • 40
  • 14
    Any idea why i get MyAppName.MyClassName out of that? I'm only interest in MyClassName – Andrew Nov 27 '16 at 21:00
  • @Andrew could you give more specific in your case? I'm using this extension in many projects and all of them response as intended. – nahung89 Nov 28 '16 at 08:09
  • 2
    Well if i call it from the class itself it return MyClassName, but if I wrap that in a method that returns the class name string and call it from another class it returns MyAppName.MyClassName. While searching around i saw that all classes are implicitly namespaced, so if you're to call it outside of your class you get MyAppName.MyClassName instead of MyClassName. Then you have to rely on string manipulation to get the class name. – Andrew Nov 28 '16 at 13:59
  • 2
    very useful extension – Hattori Hanzō Nov 08 '18 at 07:24
  • @Andrew, not sure of current working, but I remember, String(describing: type(of: self)) used to return ModuleName.ClassName at one point. I had split based on . character and fetched the last object. – BangOperator Jun 21 '19 at 05:42
39

Swift 5.2:

String(describing: type(of: self))
34

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
werediver
  • 4,667
  • 1
  • 29
  • 49
  • They changed it in Swift 3.0. Now you can get string from `type(of: self)` – Asad Ali Mar 10 '17 at 12:43
  • Updated to Swift 3. – werediver Mar 11 '17 at 09:19
  • I think this is the best way to get type name: any instance of class, based on NSObject, enum, typealiase, functions, var properties, and any types, even constants. For types, you have to use .self. For example, typeName(Int.self), typeName(true.self). Nor you need to worry about project name as part(such as AppProj.[typename]) Great! – David.Chu.ca Oct 16 '18 at 17:53
32

Swift 3.0

String(describing: MyViewController.self)

slim
  • 4,010
  • 9
  • 35
  • 42
29

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".

sethfri
  • 1,307
  • 1
  • 15
  • 31
25

In Swift 4.1 and now Swift 4.2 :

import Foundation

class SomeClass {
    class InnerClass {
        let foo: Int

        init(foo: Int) {
            self.foo = foo
        }
    }

    let foo: Int

    init(foo: Int) {
        self.foo = foo
    }
}

class AnotherClass : NSObject {
    let foo: Int

    init(foo: Int) {
        self.foo = foo
        super.init()
    }
}

struct SomeStruct {
    let bar: Int

    init(bar: Int) {
        self.bar = bar
    }
}

let c = SomeClass(foo: 42)
let s = SomeStruct(bar: 1337)
let i = SomeClass.InnerClass(foo: 2018)
let a = AnotherClass(foo: 1<<8)

If you don't have an instance around:

String(describing: SomeClass.self) // Result: SomeClass
String(describing: SomeStruct.self) // Result: SomeStruct
String(describing: SomeClass.InnerClass.self) // Result: InnerClass
String(describing: AnotherClass.self) // Result: AnotherClass

If you do have an instance around:

String(describing: type(of: c)) // Result: SomeClass
String(describing: type(of: s)) // Result: SomeStruct
String(describing: type(of: i)) // Result: InnerClass
String(describing: type(of: a)) // Result: AnotherClass
Adam
  • 4,266
  • 1
  • 21
  • 21
23

Swift 5.1

You can get class, struct, enum, protocol and NSObject names though Self.self.

print("\(Self.self)")
Victor Kushnerov
  • 3,706
  • 27
  • 56
  • Note that this may prepend the module name (differently to `String(describing: type(of: self))`) – User Apr 04 '20 at 14:51
  • Yes, it looks so concise but also prepends the module name and I'd say it is a wrong answer to the question... – hkdalex Jan 27 '21 at 15:18
  • 2
    This is not working on release build config, it will return Self as a String. Any good explanation why is this happening? – Mihai Erős Aug 17 '21 at 18:28
20

To get name of a Swift class from an object, e.g. for var object: SomeClass(), use

String(describing: type(of: object))

To get name of a Swift class from a class type, e.g. SomeClass, use:

String(describing: SomeClass.self)

Output:

"SomeClass"

Gurjit Singh
  • 1,723
  • 21
  • 27
17

You can try this way:

self.classForCoder.description()
shim
  • 9,289
  • 12
  • 69
  • 108
陈方涛
  • 171
  • 1
  • 3
  • This works great as it includes the full "namespace" (the appropriate target membership prefix) as well. – BonanzaDriver Feb 04 '16 at 21:54
  • BTW, I also found using "String(self)" where self is an instance of MyViewController works too ... it provides the same information ... Xcode 7.1. – BonanzaDriver Feb 05 '16 at 14:42
15

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()))"
Misha Karpenko
  • 2,168
  • 17
  • 18
15

Swift 5:

Way 1:

print("Class: \(String(describing: self)), Function: \(#function), line: \(#line)")

Output:

Class: <Test.ViewController: 0x7ffaabc0a3d0>, Function: viewDidLoad(), line: 15

Way 2:

print("Class: \(String(describing: type(of: self))), Function: \(#function), line: \(#line)")

Output:

Class: ViewController, Function: viewDidLoad(), line: 16
stevekohls
  • 2,214
  • 23
  • 29
Ashvin
  • 8,227
  • 3
  • 36
  • 53
13

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

let name = _stdlib_getDemangledTypeName(myViewController)
Jernej Strasner
  • 4,590
  • 29
  • 22
10

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
Paul Ardeleanu
  • 6,620
  • 2
  • 40
  • 41
  • Thanks. That's what worked for me. The only thing (at least on iOS 9) is that the subjectType was ending in ".Type", so I had to remove that part from the string. – Nikolay Suvandzhiev Jun 06 '16 at 08:11
9

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 ?? ""
    }
}
Exception
  • 785
  • 8
  • 8
  • When I attempt to use this I get the error: Could not cast value of type 'ProjectName.MyViewController' (0x1020409e8) to 'Swift.AnyObject.Type' (0x7fb96fc0dec0). – tylerSF Dec 02 '17 at 21:06
9

You can extend NSObjectProtocol in Swift 4 like this :

import Foundation

extension NSObjectProtocol {

    var className: String {
        return String(describing: Self.self)
    }
}

This will make calculated variable className available to ALL classes. Using this inside a print() in CalendarViewController will print "CalendarViewController" in console.

Siddharth Bhatt
  • 613
  • 6
  • 7
6

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
Troy
  • 5,319
  • 1
  • 35
  • 41
6

You can get the name of the class doing something like:

class Person {}
String(describing: Person.self)
Ale Mohamad
  • 372
  • 4
  • 7
5

To get class name as String declare your class as following

@objc(YourClassName) class YourClassName{}

And get class name using following syntax

NSStringFromClass(YourClassName)
Moin Uddin
  • 349
  • 5
  • 16
4

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;
}
drawnonward
  • 53,459
  • 16
  • 107
  • 112
4

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
Darkwonder
  • 1,149
  • 1
  • 13
  • 26
4

Swift 5

 NSStringFromClass(CustomClass.self)
Blazej SLEBODA
  • 8,936
  • 7
  • 53
  • 93
4

This kind of example for class var. Don't include the name of bundle.

extension NSObject {
    class var className: String {
        return "\(self)"
    }
}
Ivan Tkachenko
  • 489
  • 3
  • 10
3

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

self.className.components(separatedBy: ".").last!
Thanh Vũ Trần
  • 792
  • 6
  • 15
  • 1
    As far as I can tell there is no built-in className property in Swift classes. Did you subclass from something? – shim Dec 12 '16 at 17:45
  • @shim className is declared in Foundation but It seems that it's only available on macOS 10.10 and later. I just edited my answer. – Thanh Vũ Trần Dec 13 '16 at 10:14
  • 1
    Hm, that's weird. Why would they not include it in iOS? Also note it's an instance method on `NSObject` https://developer.apple.com/reference/objectivec/nsobject/1411337-classname – shim Dec 13 '16 at 15:53
3

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
Lumialxk
  • 6,239
  • 6
  • 24
  • 47
3

This solution will work for all the classes

Swift 5 solution:

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

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

USAGE:

class TextFieldCell: UITableVIewCell {
}

class LoginViewController: UIViewController {
  let cellClassName = TextFieldCell.className
}
DEEPAK KUMAR
  • 341
  • 4
  • 8
2

Swift 5.1 :-

You can also use generic function for get class name of object as string

struct GenericFunctions {
 static func className<T>(_ name: T) -> String {
        return "\(name)"
    }

}

Call this function by using following:-

let name = GenericFunctions.className(ViewController.self)

Happy Coding :)

dinesh sharma
  • 577
  • 10
  • 20
1

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.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • No it's not, for my class it returns (ExistentialMetatype) - relying on undocumented runtime behavior is always dangerous, especially for swift since it's still in a relatively early stage. – superarts.org Sep 23 '14 at 03:33
1

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

bob
  • 681
  • 5
  • 17
0

I use it in Swift 2.2

guard let currentController = UIApplication.topViewController() else { return }
currentController.classForCoder.description().componentsSeparatedByString(".").last!
Alexander Khitev
  • 6,417
  • 13
  • 59
  • 115
-1

In my case String(describing: self) returned something like:

< My_project.ExampleViewController: 0x10b2bb2b0>

But I'd like to have something like getSimpleName on Android.

So I've created a little extension:

extension UIViewController {

    func getSimpleClassName() -> String {
        let describing = String(describing: self)
        if let dotIndex = describing.index(of: "."), let commaIndex = describing.index(of: ":") {
            let afterDotIndex = describing.index(after: dotIndex)
            if(afterDotIndex < commaIndex) {
                return String(describing[afterDotIndex ..< commaIndex])
            }
        }
        return describing
    }

}

And now it returns:

ExampleViewController

Extending NSObject instead of UIViewController should also work. Function above is also fail-safe :)

Makalele
  • 7,431
  • 5
  • 54
  • 81
  • 1
    Thats because your passing an instance of the class name instead of a class so in the above example you should pass ExampleViewController.self – Luke Feb 03 '19 at 07:41