Me gustaría crear un protocolo con un método que tome una entrada genérica y devuelva un valor genérico.
Esto es lo que he intentado hasta ahora, pero produce el error de sintaxis.
Uso del identificador no declarado T.
¿Qué estoy haciendo mal?
protocol ApiMapperProtocol {
func MapFromSource(T) -> U
}
class UserMapper: NSObject, ApiMapperProtocol {
func MapFromSource(data: NSDictionary) -> UserModel {
var user = UserModel() as UserModel
var accountsData:NSArray = data["Accounts"] as NSArray
return user
}
}
Respuestas:
Es un poco diferente para los protocolos. Mira "Tipos asociados" en la documentación de Apple .
Así es como lo usas en tu ejemplo
protocol ApiMapperProtocol { associatedtype T associatedtype U func MapFromSource(_:T) -> U } class UserMapper: NSObject, ApiMapperProtocol { typealias T = NSDictionary typealias U = UserModel func MapFromSource(_ data:NSDictionary) -> UserModel { var user = UserModel() var accountsData:NSArray = data["Accounts"] as NSArray // For Swift 1.2, you need this line instead // var accountsData:NSArray = data["Accounts"] as! NSArray return user } }
fuente
x
es local, entonces no necesita decir explícitamente su tipo, entonceslet x = UserMapper()
.Para exponer un poco la respuesta de Lou Franco , si quisiera crear un método que usara un particular
ApiMapperProtocol
, hágalo de la siguiente manera:protocol ApiMapperProtocol { associatedtype T associatedtype U func mapFromSource(T) -> U } class UserMapper: NSObject, ApiMapperProtocol { // these typealiases aren't required, but I'm including them for clarity // Normally, you just allow swift to infer them typealias T = NSDictionary typealias U = UserModel func mapFromSource(data: NSDictionary) -> UserModel { var user = UserModel() var accountsData: NSArray = data["Accounts"] as NSArray // For Swift 1.2, you need this line instead // var accountsData: NSArray = data["Accounts"] as! NSArray return user } } class UsesApiMapperProtocol { func usesApiMapperProtocol< SourceType, MappedType, ApiMapperProtocolType: ApiMapperProtocol where ApiMapperProtocolType.T == SourceType, ApiMapperProtocolType.U == MappedType>( apiMapperProtocol: ApiMapperProtocolType, source: SourceType) -> MappedType { return apiMapperProtocol.mapFromSource(source) } }
UsesApiMapperProtocol
ahora se garantiza que solo aceptaSourceType
mensajes de correo electrónico compatibles con lo siguienteApiMapperProtocol
:let dictionary: NSDictionary = ... let uses = UsesApiMapperProtocol() let userModel: UserModel = uses.usesApiMapperProtocol(UserMapper() source: dictionary)
fuente
as!
lugar de soloas
Swift 1.2? Segundo: ¿podría decirme por qué necesitamos definirtype alias
nuevamente (es decir,typealias T = NSDictionary typealias U = UserModel
) en la clase que se ajusta al protocolo? Gracias por adelantado.as
aas!
. Consulta los foros de desarrollo.typealias T=NSDictionary
ytypealias U=UserModel
no son obligatorios. Actualicé el ejemplo para reflejar eso.Para lograr tener genéricos y además declararlo así
let userMapper: ApiMapperProtocol = UserMapper()
, debe tener una Clase Genérica conforme al protocolo que devuelve un elemento genérico.protocol ApiMapperProtocol { associatedtype I associatedType O func MapFromSource(data: I) -> O } class ApiMapper<I, O>: ApiMapperProtocol { func MapFromSource(data: I) -> O { fatalError() // Should be always overridden by the class } } class UserMapper: NSObject, ApiMapper<NSDictionary, UserModel> { override func MapFromSource(data: NSDictionary) -> UserModel { var user = UserModel() as UserModel var accountsData:NSArray = data["Accounts"] as NSArray return user } }
Ahora también se puede referir a
userMapper
comoApiMapper
que tienen una aplicación específica haciaUserMapper
:let userMapper: ApiMapper = UserMapper() let userModel: UserModel = userMapper.MapFromSource(data: ...)
fuente
userMapper
.CÓMO CREAR Y UTILIZAR EL PROTOCOLO GENÉRICO
protocolo Genérico {
associatedtype T associatedtype U func operation(_ t:T)->U
}
// usa el protocolo genérico
Prueba de estructura: genérica {
typealias T = UserModel typealias U = Any func operation(_ t: UserModel)->Any { let dict = ["name":"saurabh"] return dict }
}
fuente
Puede utilizar métodos de plantillas con borrado de tipo ...
protocol HeavyDelegate : class { func heavy<P, R>(heavy: Heavy<P, R>, shouldReturn: P) -> R } class Heavy<P, R> { typealias Param = P typealias Return = R weak var delegate : HeavyDelegate? func inject(p : P) -> R? { if delegate != nil { return delegate?.heavy(self, shouldReturn: p) } return nil } func callMe(r : Return) { } } class Delegate : HeavyDelegate { typealias H = Heavy<(Int, String), String> func heavy<P, R>(heavy: Heavy<P, R>, shouldReturn: P) -> R { let h = heavy as! H h.callMe("Hello") print("Invoked") return "Hello" as! R } } let heavy = Heavy<(Int, String), String>() let delegate = Delegate() heavy.delegate = delegate heavy.inject((5, "alive"))
fuente