437 Stimmen

Erhalten Sie den Klassennamen des Objekts als Zeichenfolge in Swift

Die Klassenbezeichnung eines Objekts als String mit folgendem Code erhalten:

object_getClassName(myViewController)

liefert etwas Ähnliches wie:

_TtC5AppName22CalendarViewController

Ich suche die reine Version: "CalendarViewController". Wie kann ich stattdessen einen bereinigten String des Klassennamens erhalten?

Ich habe einige Versuche von Fragen dazu gefunden, aber keine tatsächliche Antwort. Ist es überhaupt nicht möglich?

702voto

Rudolf Adamkovič Punkte 29868

Zeichenfolge aus einer Instanz:

String(describing: self)

Zeichenfolge aus einem Typ:

String(describing: YourType.self)

Beispiel:

struct Foo {

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

    // Instanzebene - Alternativer Weg
    var otherTypeName: String {
        let thisType = type(of: self)
        return String(describing: thisType)
    }

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

}

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

Getestet mit class, struct und enum.

230voto

mauricioconde Punkte 4704

AKTUALISIERT ZU SWIFT 5

Wir können ziemlich aussagekräftige Beschreibungen von Typnamen über die Instanzvariable über den String-Initialisierer erhalten und neue Objekte einer bestimmten Klasse erstellen

Zum Beispiel print(String(describing: type(of: object))). Wo object eine Instanzvariable wie Array, ein Dictionary, ein Int, ein NSDate usw. sein kann.

Weil NSObject die Wurzelklasse vieler Objective-C Klassenhierarchien ist, könnten Sie versuchen, eine Erweiterung für NSObject zu erstellen, um den Klassennamen jeder Unterklasse von NSObject zu erhalten. So:

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

Oder Sie könnten eine statische Funktion erstellen, deren Parameter vom Typ Any (Das Protokoll, dem alle Typen implizit entsprechen) ist und den Klassennamen als String zurückgibt. So:

class Utility{
    class func classNameAsString(_ obj: Any) -> String {
        //liefert lesbarere Ergebnisse für Dictionaries, Arrays, Int, usw.
        return String(describing: type(of: obj))
    }
} 

Jetzt können Sie so etwas machen:

class KlasseEins : UIViewController{ /* hier etwas Code */ }
class KlasseZwei : KlasseEins{ /* hier etwas Code */ }

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Den Klassennamen als String erhalten
        let dictionary: [String: CGFloat] = [:]
        let array: [Int] = []
        let int = 9
        let numFloat: CGFloat = 3.0
        let numDouble: Double = 1.0
        let klasseEins = KlasseEins()
        let klasseZwei: KlasseZwei? = KlasseZwei()
        let jetzt = 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("klasseEins = KlasseEins() -> \((KlasseEins).self)") //wir verwenden die Erweiterung
        if klasseZwei != nil {
            print("klasseZwei: KlasseZwei? = KlasseZwei() -> \(Utility.classNameAsString(klasseZwei!))") //jetzt können wir einen Forced-Value-Ausdruck verwenden und den Wert auspacken
        }
        print("jetzt = Date() -> \(Utility.classNameAsString(jetzt))")
        print("lbl = UILabel() -> \(String(describing: type(of: lbl)))") // wir verwenden den String-Initialisierer direkt

    }
}

Außerdem, sobald wir den Klassennamen als String erhalten, können wir neue Objekte dieser Klasse instanziieren:

// Instanziierung einer Klasse aus einem String
print("\nInstanziierung einer Klasse aus einem String")
let einKlassenname = klasseEins.theClassName
let einKlassenTyp = NSClassFromString(einKlassenname) as! NSObject.Type
let instanz = einKlassenTyp.init() // wir erstellen ein neues Objekt
print(String(cString: class_getName(type(of: instanz))))
print(instanz.self is KlasseEins)

Vielleicht hilft dies jemandem da draußen!.

164voto

nahung89 Punkte 7045

Swift 5

Hier ist die Erweiterung, um den typeName als Variable zu erhalten (funktioniert mit Werttyp oder Referenztyp).

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)
    }
}

Wie benutzen:

// Mit Klasse/Struktur/Aufzählung erweitern...
extension NSObject: NameDescribable {}
extension Array: NameDescribable {}
extension UIBarStyle: NameDescribable { }

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

// Ausgabe:
UITabBarController
UINavigationController
Array
UIBarStyle

40voto

Swift 5.2:

String(describing: type(of: self))

Swift 5.2:

String(describing: type(of: self))

34voto

werediver Punkte 4567

Ich schlage einen solchen Ansatz vor (sehr 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)"
}

Es verwendet weder Introspektion noch manuelles Demangling (keine Magie!).


Hier ist eine Demo:

// Swift 3

import class Foundation.NSObject

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

class GenericClass {
    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.self)) // GenericClass
print(typeName(GenericClass()))  // GenericClass

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X