Ich habe eine generische Funktion, die einen Webdienst aufruft und die JSON-Antwort zurück zu einem Objekt serialisiert.
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 */
}
Was ich versuche zu erreichen, ist das Äquivalent dieses Java-Codes
public <T> T invokeService(final String serviceURLSuffix, final Map<String, String> params,
final Class<T> classTypeToReturn) {
}
- Ist meine Methodensignatur für das, was ich erreichen möchte, korrekt?
- Ist die Angabe
AnyClass
als Parametertyp das Richtige? - Beim Aufrufen der Methode übergebe ich
MyObject.self
den Wert returnClass, erhalte jedoch den Kompilierungsfehler "Der Typ '()' des Ausdrucks kann nicht in den Typ 'String' konvertiert werden."
CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: CityInfo.self) { cityInfo in /*...*/
}
Bearbeiten:
Ich habe versucht object_getClass
, wie von holex erwähnt, aber jetzt bekomme ich:
Fehler: "Typ 'CityInfo.Type' entspricht nicht dem Protokoll 'AnyObject'"
Was muss getan werden, um dem Protokoll zu entsprechen?
class CityInfo : NSObject {
var cityName: String?
var regionCode: String?
var regionName: String?
}
swift
generics
type-inference
Jean-Francois Gagnon
quelle
quelle
CastDAO.invokeService("test", withParams: ["test" : "test"]) { (ci:CityInfo) in }
Antworten:
Sie nähern sich dem falsch: In Swift haben Klassen im Gegensatz zu Objective-C bestimmte Typen und sogar eine Vererbungshierarchie (
B
dh wenn Klasse von erbtA
, dannB.Type
erbt auch vonA.Type
):Aus diesem Grund sollten Sie nicht verwenden
AnyClass
, es sei denn , Sie wirklich zulassen wollen jede Klasse. In diesem Fall wäre der richtige TypT.Type
, da er die Verknüpfung zwischen demreturningClass
Parameter und dem Parameter des Abschlusses ausdrückt .Die Verwendung anstelle von
AnyClass
ermöglicht es dem Compiler, die Typen im Methodenaufruf korrekt abzuleiten:Jetzt gibt es das Problem, eine Instanz
T
zuhandler
erstellen, an die übergeben werden soll : Wenn Sie versuchen, den Code jetzt auszuführen, beschwert sich der Compiler, dass diesT
nicht möglich ist()
. Und das zu Recht: MussT
explizit eingeschränkt werden, damit ein bestimmter Initialisierer implementiert werden kann.Dies kann mit einem Protokoll wie dem folgenden erfolgen:
Dann müssen Sie nur noch die generischen Einschränkungen von ändern
invokeService
von<T>
bis<T: Initable>
.Trinkgeld
Wenn seltsame Fehler wie "Der Typ '()' des Ausdrucks kann nicht in 'String' konvertiert werden" angezeigt werden, ist es häufig hilfreich, jedes Argument des Methodenaufrufs in eine eigene Variable zu verschieben. Es hilft dabei, den Code einzugrenzen, der den Fehler verursacht, und Probleme mit der Typinferenz aufzudecken:
Jetzt gibt es zwei Möglichkeiten: Der Fehler wird in eine der Variablen verschoben (was bedeutet, dass der falsche Teil vorhanden ist) oder Sie erhalten eine kryptische Nachricht wie "Der Ausdruckstyp kann nicht konvertiert werden."
()
in Typ($T6) -> ($T6) -> $T5
".Die Ursache für den letzteren Fehler ist, dass der Compiler nicht in der Lage ist, auf die von Ihnen geschriebenen Typen zu schließen. In diesem Fall besteht das Problem darin, dass
T
nur der Parameter des Abschlusses verwendet wird und der von Ihnen übergebene Abschluss keinen bestimmten Typ angibt, sodass der Compiler nicht weiß, auf welchen Typ er schließen soll. Durch Ändern des Typs vonreturningClass
includeT
geben Sie dem Compiler eine Möglichkeit, den generischen Parameter zu bestimmen.quelle
T
wird verwendet, um die Beziehung zwischen demreturningClass
und dem übergebenen Objekt auszudrückencompletionHandler
. Wenn verwendetInitiable.Type
wird, geht diese Beziehung verloren.func somefunc<U>()
Sie können die Klasse von
AnyObject
über diesen Weg erhalten:Swift 3.x.
Swift 2.x.
und Sie können es später als Parameter übergeben, wenn Sie möchten.
quelle
self.dynamicType
Ich habe einen ähnlichen Anwendungsfall in swift5:
quelle
Static method … requires that 'MyDecodable.Type' conform to 'Decodable'
. Würde es Ihnen etwas ausmachen, Ihre Antwort zu aktualisieren, um einen Beispielanruf zu erhaltenloadItem
?.Type
und.self
(Typ und Metatyp) lernen muss.Verwendung
obj-getclass
:Angenommen, Selbst ist ein Stadtinfo-Objekt.
quelle
Swift 5
Nicht genau die gleiche Situation, aber ich hatte ein ähnliches Problem. Was mir schließlich geholfen hat, war Folgendes:
Dann können Sie es in einer Instanz dieser Klasse wie folgt aufrufen:
Hoffe das hilft jemandem in meiner gleichen Situation.
quelle