Daniel Galasko
Daniel Galasko

Reputation: 24247

Calling NSStringFromClass on a Swift Class in Objective-C returns module mangled name

I am aware of this question regarding how we can get a readable class name of an objective-c class in Swift.

What I want to achieve is getting the readable class name of a Swift class from inside objective-c without mangling the class name with the module.

So if I have a Swift class:

class Foo: NSObject{}

Then inside Objective-C I would love to use the convenient NSStringFromClass to convert the class name to a string.

I would expect NSStringFromClass([Foo class]) to return @"Foo" but instead it returns @"Bar.Foo" withBarbeing the module name.

I came across this Gist but it seems a little hacky and messy, is there a better way? Something that doesn't include typing the class name manually into a string would be preferred.

Upvotes: 19

Views: 19114

Answers (7)

TheCodingArt
TheCodingArt

Reputation: 3439

The reason you get "Bar.Foo" is because swift is a namespace language. I'm assuming the application you were running this in was named Bar. Hence you may get your class name using the following:

let nameSpaceClassName = NSStringFromClass(Foo)
let className = nameSpaceClassName.componentsSeparatedByString(".").last! as String

Edit:

The above is an extremely old answer that should be changed based on more recent introductions in the Swift library (from 3 and 4 at least). Note the following use of the Mirroring interfaces to properly extract a class's metadata:

import Foundation

/// A protocol that provides demangled information regarding core Swift structure naming components in a usable way.
public protocol StructureNameReflectable {
    /**
     An ordered list of domain named based components for the structure.
     - Example: A simple example would be:
     ```
     class Dog: NSObject {
        class Retriever: NSOjbect {}
    }
     let retriever = Retriever()
     ```
     
     `retriever.structuredName` would output `["Dog", "Retriever"]`
 */
    static var structureNameComponents: [String] { get }
    
    ///Outputs the structure's name in a string based form minus namespacing
    static var structureName: String { get }
    
    ///Outputs the structure's name in a string based form with namespacing
    static var namespacedStructureName: String { get }
    
    ///Outputs the bundle the structure is contained in
    static var bundle: Bundle { get }
}

extension StructureNameReflectable {
    
    public static var structureNameComponents: [String] {
        let type = Mirror(reflecting: self).subjectType
        let structureNameComponents = "\(type)".components(separatedBy: ".")
        return structureNameComponents
    }
    
    public static var structureName: String {
        var structureNameComponents = self.structureNameComponents
        
        if structureNameComponents.count > 1 && structureNameComponents.last == "Type" {
            structureNameComponents.removeLast()
        }

        return structureNameComponents.last!
    }
    
    public static var namespacedStructureName: String {
        return structureNameComponents.joined(separator: ".")
    }
}

extension StructureNameReflectable where Self: NSObject {
    public static var bundle: Bundle {
        return Bundle(for: self)
    }
    
    public static var className: String {
        return structureName
    }
}

extension NSObject: StructureNameReflectable { }

Hopefully the above will give guidance for the consistently improper use of String(describing:).

Upvotes: 11

Nandish
Nandish

Reputation: 1177

On the latest Swift below worked for me:

NSStringFromClass(type(of: yourClass!.self))

Upvotes: -1

Jim Tierney
Jim Tierney

Reputation: 4105

Swift 5.1 solution for NSStringFromClass

If you want the string description of a class name (say CustomTableViewCell) use:

String(describing: CustomTableViewCell.self)

Upvotes: 2

ullstrm
ullstrm

Reputation: 10170

BEFORE SWIFT 2.1:

Just put @objc(YourClassName) in your swift class:

@objc(YourClassName)

class YourClassName: NSObject {

}

And you can use NSStringFromClass like this:

NSStringFromClass(YourClassName.self)

It should also work from Objective-C then.


SWIFT 2.1

With Swift 2.1 a comment to this answer states that this is sufficient:

class YourClassName: NSObject {

}

And just use:

var str = String(YourClassName)

I have not tested this from Objective-C code myself though.


There's been a edit-suggestions that want to use this instead for Swift 4:

var str = String(describing: YourClassName.self)

I've not tested this from Objective-C though.

Upvotes: 39

oskarko
oskarko

Reputation: 4178

In objective-c your best option is:

NSString *yourCellName = NSStringFromClass([yourCell class]).pathExtension;

Upvotes: 6

ZaEeM ZaFaR
ZaEeM ZaFaR

Reputation: 1536

Working solution for this in Swift 2.1 is

String(MyClass)

Upvotes: 1

Tai Le
Tai Le

Reputation: 9296

Try it with Swift 2.0:

self.description().componentsSeparatedByString(".").last!

Upvotes: -3

Related Questions