Comment créer des protocoles génériques dans Swift?

J’aimerais créer un protocole avec une méthode qui prend une entrée générique et renvoie une valeur générique.

C’est ce que j’ai essayé jusqu’ici, mais cela produit l’erreur de syntaxe.

Utilisation d’identifiant non déclaré T.

Qu’est-ce que je fais 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 } } 

C’est un peu différent pour les protocoles. Regardez “Types associés” dans la documentation d’Apple .

Voici comment vous l’utilisez dans votre exemple

 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 } } 

Pour expliquer un peu la réponse de Lou Franco , si vous voulez créer une méthode utilisant un ApiMapperProtocol particulier, vous le faites ainsi:

 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 est maintenant garanti que SourceType accepte uniquement les SourceType compatibles avec le ApiMapperProtocol donné:

 let dictionary: NSDictionary = ... let uses = UsesApiMapperProtocol() let userModel: UserModel = uses.usesApiMapperProtocol(UserMapper() source: dictionary) 

Vous pouvez utiliser des méthodes de modèles avec effacement de type …

 protocol HeavyDelegate : class { func heavy(heavy: Heavy, shouldReturn: P) -> R } class Heavy { 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(heavy: Heavy, 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"))