J'ai une fonction générique qui appelle un service Web et sérialise la réponse JSON en un objet.
class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: AnyClass, completionHandler handler: ((T) -> ())) {
/* Construct the URL, call the service and parse the response */
}
Ce que j'essaie d'accomplir, c'est l'équivalent de ce code Java
public <T> T invokeService(final String serviceURLSuffix, final Map<String, String> params,
final Class<T> classTypeToReturn) {
}
- Ma signature de méthode pour ce que j'essaie d'accomplir est-elle correcte?
- Plus précisément, la spécification
AnyClass
comme type de paramètre est-elle la bonne chose à faire? - Lors de l'appel de la méthode, je passe
MyObject.self
comme valeur de retourClass, mais j'obtiens une erreur de compilation "Impossible de convertir le type de l'expression '()' en type 'String'"
CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: CityInfo.self) { cityInfo in /*...*/
}
Éditer:
J'ai essayé d'utiliser object_getClass
, comme mentionné par holex, mais maintenant j'obtiens:
erreur: "Le type 'CityInfo.Type' n'est pas conforme au protocole 'AnyObject'"
Que faut-il faire pour se conformer au protocole?
class CityInfo : NSObject {
var cityName: String?
var regionCode: String?
var regionName: String?
}
swift
generics
type-inference
Jean-François Gagnon
la source
la source
CastDAO.invokeService("test", withParams: ["test" : "test"]) { (ci:CityInfo) in }
Réponses:
Vous l'abordez de la mauvaise manière: dans Swift, contrairement à Objective-C, les classes ont des types spécifiques et ont même une hiérarchie d'héritage (c'est-à-dire que si la classe
B
hérite deA
, alorsB.Type
hérite également deA.Type
):C'est pourquoi vous ne devriez pas utiliser
AnyClass
, sauf si vous voulez vraiment autoriser n'importe quelle classe. Dans ce cas, le bon type seraitT.Type
, car il exprime le lien entre lereturningClass
paramètre et le paramètre de la fermeture.En fait, l'utiliser à la place de
AnyClass
permet au compilateur de déduire correctement les types dans l'appel de méthode:Maintenant, il y a le problème de la construction d'une instance de
T
à passerhandler
: si vous essayez d'exécuter le code maintenant, le compilateur se plaindra que ceT
n'est pas constructible avec()
. Et à juste titre:T
doit être explicitement contraint d'exiger qu'il implémente un initialiseur spécifique.Cela peut être fait avec un protocole comme le suivant:
Ensuite, il vous suffit de modifier les contraintes génériques
invokeService
de<T>
à<T: Initable>
.Pointe
Si vous obtenez des erreurs étranges comme "Impossible de convertir le type de l'expression '()' en type 'Chaîne'", il est souvent utile de déplacer chaque argument de l'appel de méthode vers sa propre variable. Cela permet de réduire le code à l'origine de l'erreur et de découvrir les problèmes d'inférence de type:
Maintenant, il y a deux possibilités: l'erreur se déplace vers l'une des variables (ce qui signifie que la mauvaise partie est là) ou vous obtenez un message cryptique comme "Impossible de convertir le type de l'expression
()
en type($T6) -> ($T6) -> $T5
".La cause de cette dernière erreur est que le compilateur n'est pas en mesure de déduire les types de ce que vous avez écrit. Dans ce cas, le problème est qu'il
T
n'est utilisé que dans le paramètre de la fermeture et que la fermeture que vous avez passée n'indique aucun type particulier, de sorte que le compilateur ne sait pas quel type déduire. En modifiant le type dereturningClass
pour inclure,T
vous donnez au compilateur un moyen de déterminer le paramètre générique.la source
T
est utilisé pour exprimer la relation entre lereturningClass
et l'objet passé àcompletionHandler
. SiInitiable.Type
est utilisé, cette relation est perdue.func somefunc<U>()
vous pouvez obtenir la classe de
AnyObject
via de cette façon:Swift 3.x
Swift 2.x
et vous pouvez le passer en tant que paramètre plus tard, si vous le souhaitez.
la source
self.dynamicType
J'ai un cas d'utilisation similaire dans swift5:
la source
Static method … requires that 'MyDecodable.Type' conform to 'Decodable'
. Pourriez-vous mettre à jour votre réponse pour donner un exemple d'appelloadItem
?.Type
et.self
(type et métatype).Utilisez
obj-getclass
:En supposant que soi-même est un objet d'information sur la ville.
la source
Swift 5
Pas exactement la même situation, mais j'avais un problème similaire. Ce qui m'a finalement aidé, c'est ceci:
Ensuite, vous pouvez l'appeler dans une instance de ladite classe comme ceci:
J'espère que cela aide quelqu'un dans ma même situation.
la source