J'essaie de créer dynamiquement un type basé sur une instance class
à l'aide de génériques, mais je rencontre des difficultés avec l'introspection de classes.
Voici les questions:
self.class
de Obj-C?AnyClass
de NSClassFromString
?AnyClass
ou sinon de taper des informations strictement à partir d'un paramètre générique T
? (Similaire à la syntaxe typeof(T)
de C #)Eh bien, pour un, l'équivalent Swift de [NSString class]
est .self
(voir documents métatype , bien qu'ils soient assez minces).
En fait, NSString.class
ne fonctionne même pas! Vous devez utiliser NSString.self
.
let s = NSString.self
var str = s()
str = "asdf"
De même, avec une classe Swift, j'ai essayé ...
class MyClass {
}
let MyClassRef = MyClass.self
// ERROR :(
let my_obj = MyClassRef()
Hmm… l'erreur dit:
Echec de l'exécution du terrain de jeu: erreur:: 16: 1: erreur: la construction d'un objet de type classe 'X' avec une valeur de métatype requiert un initialiseur '@ requis'
Y().me() ^ <REPL>:3:7: note: selected implicit initializer with type '()' class X { ^
Il m'a fallu un certain temps pour comprendre ce que cela signifiait… il s'est avéré qu'il souhaitait que la classe ait une @required init()
class X {
func me() {
println("asdf")
}
required init () {
}
}
let Y = X.self
// prints "asdf"
Y().me()
Certains docs se réfèrent à ceci sous le nom de .Type
, mais MyClass.Type
me donne une erreur dans le terrain de jeu.
Voici comment utiliser NSClassFromString
. Vous devez connaître la super-classe de ce que vous allez finir avec. Voici une paire superclasse-sous-classe qui sait se décrire pour println
:
@objc(Zilk) class Zilk : NSObject {
override var description : String {return "I am a Zilk"}
}
@objc(Zork) class Zork : Zilk {
override var description : String {return "I am a Zork"}
}
Notez l'utilisation de la syntaxe spéciale @obj
pour dicter le nom fourni Objective-C de ces classes; c'est crucial, car sinon nous ne connaissons pas la chaîne munged qui désigne chaque classe.
Maintenant, nous pouvons utiliser NSClassFromString
pour créer la classe Zork ou la classe Zilk, car nous savons que nous pouvons le taper comme un objet NSObject et ne pas planter plus tard:
let aClass = NSClassFromString("Zork") as NSObject.Type
let anObject = aClass()
println(anObject) // "I am a Zork"
Et c'est réversible. println(NSStringFromClass(anObject.dynamicType))
fonctionne également.
Si je lis bien la documentation, si vous traitez des instances et par exemple, voulez renvoyer une nouvelle instance du même type que l'objet qui vous a été fourni et le type peut être construit avec un init (), vous pouvez faire:
let typeOfObject = aGivenObject.dynamicType
var freshInstance = typeOfObject()
Je l'ai rapidement testé avec String:
let someType = "Fooo".dynamicType
let emptyString = someType()
let threeString = someType("Three")
qui a bien fonctionné.
Dans Swift
object.dynamicType
est obsolète.
Utilisez plutôt:
type(of:object)
protocol Decoratable{}
class A:Decoratable{}
class B:Decoratable{}
let object:AnyObject = A()
object.dynamicType is A.Type//true
object.dynamicType is B.Type//false
object.dynamicType is Decoratable.Type//true
NOTE: Notez que cela fonctionne aussi avec les protocoles que l'objet peut ou non s'étendre
Voici un autre exemple montrant l'implémentation d'une hiérarchie de classes, similaire à la réponse acceptée, mis à jour pour la première version de Swift.
class NamedItem : NSObject {
func display() {
println("display")
}
required override init() {
super.init()
println("base")
}
}
class File : NamedItem {
required init() {
super.init()
println("folder")
}
}
class Folder : NamedItem {
required init() {
super.init()
println("file")
}
}
let y = Folder.self
y().display()
let z = File.self
z().display()
Imprime ce résultat:
base
file
display
base
folder
display
Enfin obtenu quelque chose à travailler. C'est un peu paresseux mais même la route NSClassFromString () ne m'a pas fonctionné ...
import Foundation
var classMap = Dictionary<String, AnyObject>()
func mapClass(name: String, constructor: AnyObject) -> ()
{
classMap[name] = constructor;
}
class Factory
{
class func create(className: String) -> AnyObject?
{
var something : AnyObject?
var template : FactoryObject? = classMap[className] as? FactoryObject
if (template)
{
let somethingElse : FactoryObject = template!.dynamicType()
return somethingElse
}
return nil
}
}
import ObjectiveC
class FactoryObject : NSObject
{
@required init() {}
//...
}
class Foo : FactoryObject
{
class override func initialize()
{
mapClass("LocalData", LocalData())
}
init () { super.init() }
}
var makeFoo : AnyObject? = Factory.create("Foo")
et bingo, "makeFoo" contient une instance Foo.
L'inconvénient est que vos classes doivent dériver de FactoryObject et elles DOIVENT avoir la méthode d'initialisation Obj-C + afin que votre classe soit automatiquement insérée dans la carte de classes par la fonction globale "mapClass".