31

Is there an equivalent of NSStringFromClass in Swift that gives a user-readable version of the class name? I've tried to use it with a native Swift class I created, but as you can see, the result seems to be the compiler's internal representation of the class name:

println(NSStringFromClass(MyClass.self))

Result:

_TtC5test7MyClass

I've tried adding the @objc attribute to the class, and making it a subclass of NSObject, but it makes no difference. I've discovered that if I replace MyClass with an Objective-C class of the same name, and import this in the bridging header, it gives me 'MyClass', but this shouldn't be necessary.

Another option would be to make a protocol for this, which each class I want to use in this way must conform to:

protocol Nameable {
    class var className: String { get }
}

However, it would be easier to have a built-in way to do this in the language.

jfla
  • 568
  • 2
  • 6
  • 12

15 Answers15

62

You can now just do:

String(MyClass)
NatashaTheRobot
  • 6,879
  • 4
  • 32
  • 27
  • This makes me unreasonably happy! Thanks Natasha robot. – fractious Jan 15 '16 at 11:44
  • 7
    In Swift 3 this doesn't work anymore. The Swift 3 converter changed it to String(describing: MyClass) but that's not working either. – shim Sep 14 '16 at 04:32
  • 1
    @shim have you tried `String(describing: self)` or just passing object `let object = MyClass()` `String(describing: object)` – Apan Sep 14 '16 at 11:11
25

new format based on xcode 6 beta 5.

(project_name).(class_name)

func getName(classType:AnyClass) -> String {

    let classString = NSStringFromClass(classType.self)
    let range = classString.rangeOfString(".", options: NSStringCompareOptions.CaseInsensitiveSearch, range: Range<String.Index>(start:classString.startIndex, end: classString.endIndex), locale: nil)
    return classString.substringFromIndex(range!.endIndex)
}

Latest 6.3 Xcode Swift 1.2

if you need an extension or you can put this on any common object:

public extension NSObject{
    public class var nameOfClass: String{
        return NSStringFromClass(self).componentsSeparatedByString(".").last!
    }

    public var nameOfClass: String{
        return NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
    }
}
ImpactZero
  • 547
  • 4
  • 8
19

Swift 3

type(of: self) prints ModuleName.ClassName

String(describing: type(of: self)) prints ClassName

Timonea
  • 206
  • 2
  • 2
5

At the moment, there's no reliable way to do this. See an Apple developer's comment on https://devforums.apple.com/thread/227425

Swift does not currently have much in the way of introspection.

There is some introspection machinery that is used for the playgrounds. I don't know if that is intended to be API.

Some Swift methods and variables can be examined using the Objective-C runtime's introspection. That's likely to be the best solution today.

Swift does have the notion of a metatype, somewhat analogous to the Class type in Objective C. You can find it using TypeName.self, e.g.:

class Foo {
    @required  init() {
    }
}

var normalFoo : Foo = Foo()
var fooType : Foo.Type = Foo.self;
var fooFromMetatype : Foo = fooType();

Perhaps, by release time, metatypes will include more introspection abilities. I suggest filing a Radar feature request for this.

Community
  • 1
  • 1
Adam Wright
  • 48,938
  • 12
  • 131
  • 152
5

In Swift 2 beta 4 you can get to the information via the type object:

let className = "\(String.self)"   // gives: "Swift.String"

or if you have an instance:

let s = "Hello World"
let className = "\(s.dynamicType)" // gives: "Swift.String"

You get the Module.Class result, like:

Swift.String
ABC.MyGenericClass<Swift.Int>

Funny enough the Type object returned does not seem to conform to the CustomStringConvertible protocol. Hence it has no 'description' property, though the "" pattern still does the right thing.

P.S.: Before b4 the same could be accomplished via reflect(obj.dynamicType).summary.

hnh
  • 13,957
  • 6
  • 30
  • 40
  • That's cool but until they have an explicit className() method somewhere in there I am a little wary. Summary might be the class name right now but there are no guarantees it'll stay that way. – n13 Jun 28 '15 at 00:56
3

----- Updated -----

As @ThomasW mentioned, for Swift 4, we need to use String(describing:type(of:self))

----- Old post ----

I prefer to use String(self.dynamicType)

Use it in my project https://github.com/JakeLin/SwiftWeather/blob/e7165b0919dda53fd7fcba9b43fdfe150d73c6f8/SwiftWeather/ForecastView.swift#L135

Jake Lin
  • 11,146
  • 6
  • 29
  • 40
3

In Swift v3.0, this worked for me:

String.init(describing: self.self)
Coach Roebuck
  • 904
  • 2
  • 12
  • 20
1

If you want to have only the name of the class in swift you can parse the string returned by NSStringFromClass().

This is done in nameOfClass.swift of the INSwift Github repository: https://github.com/indieSoftware/INSwift

David Moles
  • 48,006
  • 27
  • 136
  • 235
Sven
  • 11
  • 1
  • Note that this only works with class types -- if you try it with say a protocol Swift will complain `error: type 'MyProtocol' does not conform to protocol 'AnyObject'` – David Moles Jul 17 '14 at 03:05
1

You shouls now be able to use the following to retrieve the class name in swift

let nameSpaceClassName = NSStringFromClass(RWTCountryPopoverViewController.self)
let className = nameSpaceClassName.componentsSeparatedByString(".").last! as String
TheCodingArt
  • 3,436
  • 4
  • 30
  • 53
1

This is a bit shorter. No need of NSStringFromClass

MyObject.self.description().componentsSeparatedByString(".").last!
nacho4d
  • 43,720
  • 45
  • 157
  • 240
1

Here is Swift 3+, Xcode 8+ example with code:

class MySuperbClass{
    let a = 4
    func getClassName() -> String? {
        return String(describing: type(of:self)).components(separatedBy: ".").first
    }
}


let className = String(describing: type(of:MySuperbClass.self)).components(separatedBy: ".").first
//className = "MySuperbClass" 
let classNameFromObject = MySuperbClass().getClassName()
//classNameFromObject = "MySuperbClass"
Rafat touqir Rafsun
  • 2,777
  • 28
  • 24
1

Swift 4

super.init(nibName:String(describing:MyClass.self), bundle: nil)
DMagaro
  • 11
  • 1
0
myObject.description().componentsSeparatedByString(" ").first!

This is not exactly what you want - it will add an unwanted leading '<' and trailing ':'. But when I am debugging I value speed over neatness so this quick + dirty trick worked for me.

Rolf Hendriks
  • 411
  • 4
  • 8
0

Swift 3

NSStringFromClass(self).components(separatedBy: ".").last!
anoop4real
  • 7,598
  • 4
  • 53
  • 56
0

In latest version of swift, below works for me:

NSStringFromClass(type(of: device!.self))
Nandish
  • 1,136
  • 9
  • 16