Obtenir le nom de classe d'un objet sous forme de chaîne à l'aide de
object_getClassName(myViewController)
retourne quelque chose comme ça
_TtC5AppName22CalendarViewController
Je cherche la version pure : "CalendarViewController". Comment puis-je obtenir un nettoyé chaîne du nom de la classe?
J'ai trouvé quelques tentatives de questions à ce sujet mais pas une réponse réelle. N'est-ce pas possible?
Chaîne d'un instance:
String(describing: YourType.self)
Chaîne d'un type:
String(describing: self)
Exemple:
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"
Testé avec class
, struct
et enum
.
MISE À JOUR VERS 4.2
On peut obtenir de jolies descriptions des noms de types en utilisant la variable d'instance via l'initialiseur String
et créer de nouveaux objets d'une certaine classe
J'aime, par exemple print(String(describing: type(of: object)))
. Où object
peut être un variable d'instance comme un tableau, un dictionnaire, une Int
, une NSDate
, etc.
Comme NSObject
est la classe racine de la plupart des hiérarchies de classes Objective-C, vous pouvez essayer de créer une extension pour NSObject
afin d’obtenir le nom de classe de chaque sous-classe de NSObject
. Comme ça:
extension NSObject {
var theClassName: String {
return NSStringFromClass(type(of: self))
}
}
Vous pouvez également créer une fonction statique dont le paramètre est de type Any
(protocole auquel tous les types se conforment implicitement) et renvoyer le nom de la classe sous forme de chaîne. Comme ça:
class Utility{
class func classNameAsString(_ obj: Any) -> String {
//prints more readable results for dictionaries, arrays, Int, etc
return String(describing: type(of: obj))
}
}
Maintenant, vous pouvez faire quelque chose comme ça:
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("diccionary: [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
}
}
De plus, une fois que nous pouvons obtenir le nom de la classe sous la forme String, nous pouvons instancier de nouveaux objets de cette classe:
// Instanciate a class from a String
print("\nInstaciate 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)
Peut-être que cela aide quelqu'un là-bas!.
Voici l'extension pour obtenir la variable typeName
en tant que variable (pour le type de valeur ou le type de référence).
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)
}
}
Comment utiliser:
// Extend with class/struct/enum...
extension NSObject: NameDescribable {}
extension Array: NameDescribable {}
print(UITabBarController().typeName)
print(UINavigationController.typeName)
print([Int]().typeName)
Je suggère une telle approche ( 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)"
}
Il n’utilise ni introspection ni démêlage manuel ( pas de magie! ).
Voici une démo:
// 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
Si vous avez le type Foo
, le code suivant vous donnera "Foo"
dans Swift 3 et Swift 4:
let className = String(describing: Foo.self) // Gives you "Foo"
Le problème avec la plupart des réponses ici est qu’elles vous donnent "Foo.Type"
comme chaîne résultante lorsque vous n’avez aucune instance du type, alors que ce que vous voulez vraiment est juste "Foo"
. Ce qui suit vous donne "Foo.Type"
, comme mentionné dans un tas d’autres réponses.
let className = String(describing: type(of: Foo.self)) // Gives you "Foo.Type"
La partie type(of:)
est inutile si vous voulez juste "Foo"
.
Dans Swift 4.1 et maintenant 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)
Si vous n'avez pas d'instance autour:
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
Si vous avez une instance autour de:
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
Vous pouvez utiliser la fonction de bibliothèque standard Swift appelée _stdlib_getDemangledTypeName
comme ceci:
let name = _stdlib_getDemangledTypeName(myViewController)
Pour obtenir le nom du type sous forme de chaîne dans Swift 4 (je n'ai pas vérifié les versions précédentes), utilisez simplement une interpolation de chaîne:
"\(type(of: myViewController))"
Vous pouvez utiliser .self
sur un type lui-même et la fonction type(of:_)
sur une instance:
// Both constants will have "UIViewController" as their value
let stringFromType = "\(UIViewController.self)"
let stringFromInstance = "\(type(of: UIViewController()))"
Vous pouvez essayer de cette façon:
self.classForCoder.description()
On peut aussi utiliser des miroirs:
let vc = UIViewController()
String(Mirror(reflecting: vc).subjectType)
NB: Cette méthode peut également être utilisée pour Structs et Enums. Il y a un displayStyle qui donne une indication de quel type de la structure:
Mirror(reflecting: vc).displayStyle
Le retour est une énumération afin que vous puissiez:
Mirror(reflecting: vc).displayStyle == .Class
Swift 3.0: Vous pouvez créer une extension comme celle-ci .. Elle renvoie le nom de la classe sans le nom du projet.
extension NSObject {
var className: String {
return NSStringFromClass(self as! AnyClass).components(separatedBy: ".").last ?? ""
}
public class var className: String {
return NSStringFromClass(self).components(separatedBy: ".").last ?? ""
}
}
Je cherche cette réponse par intermittence depuis un moment. J'utilise GKStateMachine et j'aime observer les changements d'état et je voulais un moyen facile de voir uniquement le nom de la classe. Je ne sais pas s'il s'agit uniquement de iOS 10 ou de Swift 2.3, mais dans cet environnement, les éléments suivants remplissent exactement ce que je veux:
let state:GKState?
print("Class Name: \(String(state.classForCoder)")
// Output:
// Class Name: GKState
Essayez reflect().summary
sur la classe self ou l’instance dynamicType. Décompressez les options avant d’obtenir dynamicType, sinon, dynamicType est l’encapsuleur facultatif.
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;
Le résumé est un chemin de classe avec les types génériques décrits. Pour obtenir un nom de classe simple à partir du résumé, essayez cette méthode.
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;
}
Les solutions ci-dessus ne fonctionnaient pas pour moi. Le produit principalement les questions mentionnent dans plusieurs commentaires:
MonNomApp.NomClasse
ou
MyFrameWorkName.ClassName
Cette solution fonctionnait sous XCode 9, Swift 3.0:
Je l'ai nommé classNameCleaned
pour qu'il soit plus facile d'accès et n'entre pas en conflit avec les futures modifications de className()
:
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
Vous pouvez étendre NSObjectProtocol
dans Swift 4 comme ceci:
import Foundation
extension NSObjectProtocol {
var className: String {
return String(describing: Self.self)
}
}
Cela rendra la variable calculée className
disponible pour TOUTES les classes. L'utilisation de ceci dans une print()
dans CalendarViewController
imprimera "CalendarViewController"
dans la console.
Pour obtenir le nom de la classe sous forme de chaîne, déclarez votre classe comme suit
@objc(YourClassName) class YourClassName{}
Et obtenez le nom de la classe en utilisant la syntaxe suivante
NSStringFromClass(YourClassName)
Pour obtenir le nom d'une classe Swift à partir d'un objet, par exemple pour l'objet var: SomeClass (), utilisez
String(describing: type(of: object))
Pour obtenir le nom d'une classe Swift à partir d'un type de classe, par exemple SomeClass, utilisez:
String(describing: SomeClass.self)
Sortie:
"SomeClass"
Swift 3.0 (macOS 10.10 et supérieur), vous pouvez l'obtenir à partir de className
self.className.components(separatedBy: ".").last!
Si vous n'aimez pas le nom mutilé, vous pouvez dicter votre propre nom:
@objc(CalendarViewController) class CalendarViewController : UIViewController {
// ...
}
Cependant, il serait préférable à la longue d'apprendre à analyser le nom mutilé. Le format est standard et significatif et ne changera pas.
Vous pouvez obtenir le nom de la classe en faisant quelque chose comme:
class Person {}
String(describing: Person.self)
Je l'utilise dans Swift 2.2
guard let currentController = UIApplication.topViewController() else { return }
currentController.classForCoder.description().componentsSeparatedByString(".").last!
Parfois, les autres solutions donneront un nom non utile en fonction de l'objet que vous essayez de regarder. Dans ce cas, vous pouvez obtenir le nom de la classe sous forme de chaîne en utilisant ce qui suit.
String(cString: object_getClassName(Any!))
Cliquez sur la fonction dans xcode pour voir des méthodes connexes assez utiles. ou vérifiez ici https://developer.Apple.com/reference/objectivec/objective_c_functions