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
AnyClass
como tipo de parámetro? - Cuando llamo al método, lo paso
MyObject.self
como 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
B
hereda deA
, entoncesB.Type
tambié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 elreturningClass
parámetro y el parámetro del cierre.De hecho, usarlo en lugar de
AnyClass
permite al compilador inferir correctamente los tipos en la llamada al método:Ahora está el problema de construir una instancia
T
para pasarhandler
: si intenta ejecutar el código en este momento, el compilador se quejará de queT
no es constructible()
. Y con razón:T
tiene 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
invokeService
from<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
T
solo 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 dereturningClass
incluir,T
le da al compilador una forma de determinar el parámetro genérico.fuente
T
se utiliza para expresar la relación entrereturningClass
y el objeto al que se pasacompletionHandler
. SiInitiable.Type
se usa esta relación se pierde.func somefunc<U>()
puede obtener la clase de
AnyObject
esta manera:Swift 3.x
Swift 2.x
y puede pasarlo como parámetro más tarde, si lo desea.
fuente
self.dynamicType
Tengo 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
?.Type
y.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