Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get a user-readable version of the class name in swift (in objc NSStringFromClass was fine)

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.

like image 242
jfla Avatar asked Jun 08 '14 15:06

jfla


6 Answers

You can now just do:

String(MyClass)
like image 155
NatashaTheRobot Avatar answered Nov 14 '22 08:11

NatashaTheRobot


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!
    }
}
like image 39
ImpactZero Avatar answered Nov 14 '22 07:11

ImpactZero


Swift 3

type(of: self) prints ModuleName.ClassName

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

like image 38
Timonea Avatar answered Nov 14 '22 07:11

Timonea


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.

like image 43
Adam Wright Avatar answered Nov 14 '22 07:11

Adam Wright


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.

like image 5
hnh Avatar answered Nov 14 '22 07:11

hnh


In Swift v3.0, this worked for me:

String.init(describing: self.self)
like image 3
Coach Roebuck Avatar answered Nov 14 '22 09:11

Coach Roebuck