125 votes

Introspection rapide des classes et génériques

Je suis en train de créer dynamiquement un class exemple type de l'utilisation de génériques, cependant je rencontre des difficultés avec la classe de l'introspection.

Voici les questions:

  • Est-il un Swift-équivalent à l'Obj-C self.class?
  • Est-il possible d'instancier une classe à l'aide de l' AnyClass résultat d' NSClassFromString?
  • Est-il un moyen pour obtenir de l' AnyClass ou autre type d'information strictement à partir d'un paramètre générique T? (Similaire à C#' typeof(T) de la syntaxe)

109voto

Jiaaro Points 14379

Eh bien, pour l'un, la Swift équivalent de [NSString class] est .self (voir Metatype docs, mais elles sont assez fines).

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 swift de la classe, j'ai essayé...

class MyClass {

}

let MyClassRef = MyClass.self

// ERROR :(
let my_obj = MyClassRef()

Hmm... le message d'erreur indique:

Aire de jeux de l'exécution a échoué: erreur: :16:1: erreur: construction d'un objet de type classe " X " avec un metatype valeur implique un '@required' initialiseur

 Y().me()
 ^
 <REPL>:3:7: note: selected implicit initializer with type '()'
 class X {
       ^

Il m'a fallu un certain temps à comprendre ce que cela signifie... il s'avère qu'elle veut la classe d'avoir un @required init()

class X {
    func me() {
        println("asdf")
    }

    @required init () {

    }
}

let Y = X.self

// prints "asdf"
Y().me()

Certains des docs se référer à ce que .Type, mais MyClass.Type me donne une erreur dans la cour de récréation.

49voto

matt Points 60113

Voici comment utiliser NSClassFromString. Vous devez savoir la super-classe de ce que vous allez finir. Voici une super-classe-sous-classe de la paire qui savent comment décrire eux-mêmes 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"}
}

Remarquez l'utilisation de la @obj de la syntaxe de dicter l'Objective-C munged nom de ces classes; que c'est essentiel, parce que sinon, nous ne connaissons pas la munged chaîne de caractères qui désigne chaque classe.

Maintenant, nous pouvons utiliser NSClassFromString pour faire de la Zork de la classe ou de l'Zilk classe, parce que nous savons que nous pouvons taper comme un NSObject et ne pas planter plus tard:

let aClass = NSClassFromString("Zork") as NSObject.Type
let anObject = aClass()
println(anObject) // "I am a Zork"

Et il est réversible; println(NSStringFromClass(anObject.dynamicType)) fonctionne également.

13voto

monkeydom Points 2148

Si je lis correctement la documentation, si vous traitez des instances et souhaitez par exemple renvoyer une nouvelle instance du même type que l'objet qui vous a été fourni et que le type peut être construit avec un init (), vous pouvez procéder comme suit:

 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é.

1voto

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".

1voto

possen Points 595

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
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X