2017-09-01 5 views
0

J'essaie d'instancier une nouvelle classe à partir d'un nom de classe de chaîne, comme on peut le faire facilement en Java. Je l'ai finalement écrit cette fonction:Swift: réflexion grâce à infoDictionary

func stringClassFromString(_ className: String) -> AnyClass! { 
    let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String; 
    let cls: AnyClass = NSClassFromString("\(namespace).\(className)")!; 
    return cls; 
} 

Merci à quelques googler, mais dès que j'ai essayé cette solution grâce à un test unitaire:

func test() { 
    let myclass = stringClassFromString("NSDate") as! NSDate.Type 
    let instance = myclass.init() 
    print(instance) 
} 

J'ai une exception (Discussion 1: EXC_BAD_INSTRUCTION (code = EXC_I386_INVOP, sous-code = 0x0)) dès que mon test utilise la ligne: let namespace ... J'ai essayé de voir le contenu de l'infoDictionary, il est vide. Donc ma question est simple, est-ce à cause du contexte des tests unitaires que mon dictionnaire est vide? Y at-il une méthode ou une bibliothèque (comme robolectric pour Android) pour simuler un infoDicionary à des fins de test.

+1

Pourquoi voudriez-vous instancier une classe à partir d'un nom de classe String? L'un des plus grands avantages de Swift est son vérificateur de type statique, que vous ignorez complètement lorsque vous essayez de créer des classes à partir d'identifiants dynamiques. De plus, essayez d'utiliser des classes Swift natives lorsqu'elles sont disponibles au lieu de celles de Foundation (telles que 'Date' au lieu de' NSDate'). –

+0

J'apprends le développement rapide et la réflexion qui, je pense, peuvent être intéressants à apprendre. Merci pour vos conseils, j'évite d'utiliser les cours de Foundation mais ici c'était juste un exemple. – zed13

+2

Si vous êtes dans les premiers stades de l'apprentissage Swift, ne vous embêtez pas avec la réflexion. Apprenez les bases du système de type d'abord et plus tard si vous trouvez un problème que vous ne pouvez vraiment pas résoudre tout en utilisant pleinement le vérificateur de type statique, puis jetez un coup d'oeil aux réflexions. –

Répondre

0

je réussis à trouver mon erreur, au lieu d'utiliser le principal Bundle, j'utilise le constructeur de la classe Bundle pour construire un Bundle qui correspondra au contexte actuel:

let namespace = Bundle(for: type(of: self)).infoDictionary!["CFBundleExecutable"] as! String; 

Et Tadda, il travaille !