Tengo una función genérica que llama a un servicio web y serializa la respuesta JSON a un objeto.
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 */
}
Lo que intento lograr es el equivalente de este código Java
public <T> T invokeService(final String serviceURLSuffix, final Map<String, String> params,
final Class<T> classTypeToReturn) {
}
- ¿Es correcta la firma de mi método para lo que estoy tratando de lograr?
- Más específicamente, ¿es lo que se debe especificar
AnyClasscomo tipo de parámetro? - Cuando llamo al método, lo paso
MyObject.selfcomo el valor returnClass, pero aparece un error de compilación "No se puede convertir el tipo de expresión '()' para escribir 'String'"
CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: CityInfo.self) { cityInfo in /*...*/
}
Editar:
Intenté usar object_getClass, como mencionó holex, pero ahora obtengo:
error: "Tipo 'CityInfo.Type' no se ajusta al protocolo 'AnyObject'"
¿Qué hay que hacer para cumplir con el protocolo?
class CityInfo : NSObject {
var cityName: String?
var regionCode: String?
var regionName: String?
}
swift
generics
type-inference
Jean-Francois Gagnon
fuente
fuente

CastDAO.invokeService("test", withParams: ["test" : "test"]) { (ci:CityInfo) in }Respuestas:
Lo estás abordando de manera incorrecta: en Swift, a diferencia de Objective-C, las clases tienen tipos específicos e incluso tienen una jerarquía de herencia (es decir, si la clase
Bhereda deA, entoncesB.Typetambién hereda deA.Type):Es por eso que no debes usar
AnyClass, a menos que realmente quieras permitir cualquier clase. En este caso, el tipo correcto seríaT.Type, porque expresa el vínculo entre elreturningClassparámetro y el parámetro del cierre.De hecho, usarlo en lugar de
AnyClasspermite al compilador inferir correctamente los tipos en la llamada al método:Ahora está el problema de construir una instancia
Tpara pasarhandler: si intenta ejecutar el código en este momento, el compilador se quejará de queTno es constructible(). Y con razón:Ttiene que estar explícitamente restringido para requerir que implemente un inicializador específico.Esto se puede hacer con un protocolo como el siguiente:
Entonces solo tiene que cambiar las restricciones genéricas de
invokeServicefrom<T>a<T: Initable>.Propina
Si obtiene errores extraños como "No se puede convertir el tipo de expresión '()' a tipo 'Cadena'", a menudo es útil mover cada argumento de la llamada al método a su propia variable. Ayuda a reducir el código que está causando el error y descubrir problemas de inferencia de tipos:
Ahora hay dos posibilidades: el error se mueve a una de las variables (lo que significa que la parte incorrecta está allí) o aparece un mensaje críptico como "No se puede convertir el tipo de expresión
()en tipo($T6) -> ($T6) -> $T5".La causa del último error es que el compilador no puede inferir los tipos de lo que escribió. En este caso, el problema es que
Tsolo se usa en el parámetro del cierre y el cierre que pasó no indica ningún tipo en particular, por lo que el compilador no sabe qué tipo inferir. Al cambiar el tipo dereturningClassincluir,Tle da al compilador una forma de determinar el parámetro genérico.fuente
Tse utiliza para expresar la relación entrereturningClassy el objeto al que se pasacompletionHandler. SiInitiable.Typese usa esta relación se pierde.func somefunc<U>()puede obtener la clase de
AnyObjectesta manera:Swift 3.x
Swift 2.x
y puede pasarlo como parámetro más tarde, si lo desea.
fuente
self.dynamicTypeTengo un caso de uso similar en swift5:
fuente
Static method … requires that 'MyDecodable.Type' conform to 'Decodable'. ¿Te importaría actualizar tu respuesta para llamar a un ejemploloadItem?.Typey.self(tipo y metatipo).Uso
obj-getclass:Asumir uno mismo es un objeto de información de la ciudad.
fuente
Swift 5
No es exactamente la misma situación, pero estaba teniendo un problema similar. Lo que finalmente me ayudó fue esto:
Luego puede llamarlo dentro de una instancia de dicha clase como esta:
Espero que esto ayude a alguien en mi misma situación.
fuente