Eu tenho uma função genérica que chama um serviço web e serializa a resposta JSON de volta para um 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 */
}
O que estou tentando realizar é o equivalente a este código Java
public <T> T invokeService(final String serviceURLSuffix, final Map<String, String> params,
final Class<T> classTypeToReturn) {
}
- Minha assinatura de método para o que estou tentando realizar está correta?
- Mais especificamente, especificar
AnyClass
como tipo de parâmetro a coisa certa a fazer? - Ao chamar o método, estou passando
MyObject.self
como o valor returnClass, mas recebo um erro de compilação "Não é possível converter o tipo da expressão '()' para o tipo 'String'"
CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: CityInfo.self) { cityInfo in /*...*/
}
Editar:
Tentei usar object_getClass
, como mencionado pela holex, mas agora recebo:
erro: "O tipo 'CityInfo.Type' não está em conformidade com o protocolo 'AnyObject'"
O que precisa ser feito para estar em conformidade com o protocolo?
class CityInfo : NSObject {
var cityName: String?
var regionCode: String?
var regionName: String?
}
swift
generics
type-inference
Jean-Francois Gagnon
fonte
fonte
CastDAO.invokeService("test", withParams: ["test" : "test"]) { (ci:CityInfo) in }
Respostas:
Você está abordando isso da maneira errada: no Swift, ao contrário do Objective-C, as classes têm tipos específicos e até uma hierarquia de herança (ou seja, se a classe é
B
herdada deA
, entãoB.Type
também é herdada deA.Type
):É por isso que você não deve usar
AnyClass
, a menos que queira realmente permitir qualquer aula. Nesse caso, o tipo correto seriaT.Type
, porque expressa o link entre oreturningClass
parâmetro e o parâmetro do fechamento.De fato, usá-lo em vez de
AnyClass
permitir que o compilador deduza corretamente os tipos na chamada do método:Agora existe o problema de construir uma instância
T
para a qual passarhandler
: se você tentar executar o código agora, o compilador reclamará queT
não é construtível()
. E com razão:T
deve ser explicitamente restringido para exigir que implemente um inicializador específico.Isso pode ser feito com um protocolo como o seguinte:
Então você só precisa alterar as restrições genéricas de
invokeService
de<T>
para<T: Initable>
.Dica
Se você receber erros estranhos como "Não é possível converter o tipo da expressão '()' para o tipo 'String'", geralmente é útil mover todos os argumentos da chamada de método para sua própria variável. Ajuda a restringir o código que está causando o erro e a descobrir problemas de inferência de tipo:
Agora, existem duas possibilidades: o erro é movido para uma das variáveis (o que significa que a parte errada está lá) ou você recebe uma mensagem enigmática como "Não é possível converter o tipo da expressão
()
em tipo($T6) -> ($T6) -> $T5
".A causa do último erro é que o compilador não pode inferir os tipos do que você escreveu. Nesse caso, o problema é que isso
T
é usado apenas no parâmetro do fechamento e o fechamento que você passou não indica nenhum tipo específico, portanto o compilador não sabe que tipo inferir. Alterando o tipo dereturningClass
inclusão,T
você fornece ao compilador uma maneira de determinar o parâmetro genérico.fonte
T
é usado para expressar a relação entre oreturningClass
e o objeto passado paracompletionHandler
. SeInitiable.Type
for usado, esse relacionamento será perdido.func somefunc<U>()
você pode obter a aula
AnyObject
dessa maneira:Swift 3.x
Swift 2.x
e você pode passá-lo como paramater mais tarde, se desejar.
fonte
self.dynamicType
Eu tenho um caso de uso semelhante no swift5:
fonte
Static method … requires that 'MyDecodable.Type' conform to 'Decodable'
. Você se importaria de atualizar sua resposta para dar um exemplo de chamadaloadItem
?.Type
e.self
(tipo e metatipo).Use
obj-getclass
:Supondo que o self é um objeto de informações da cidade.
fonte
Swift 5
Não é exatamente a mesma situação, mas eu estava tendo um problema semelhante. O que finalmente me ajudou foi isso:
Então você pode chamá-lo dentro de uma instância da referida classe como esta:
Espero que isso ajude alguém na minha mesma situação.
fonte