Je veux créer une classe qui peut stocker des objets conformes à un certain protocole. Les objets doivent être stockés dans un tableau typé. Selon la documentation Swift, les protocoles peuvent être utilisés comme types:
Comme il s'agit d'un type, vous pouvez utiliser un protocole dans de nombreux endroits où d'autres types sont autorisés, notamment:
- En tant que type de paramètre ou type de retour dans une fonction, une méthode ou un initialiseur
- En tant que type d'une constante, d'une variable ou d'une propriété
- En tant que type d'éléments dans un tableau, un dictionnaire ou un autre conteneur
Cependant, ce qui suit génère des erreurs de compilation:
Le protocole 'SomeProtocol' ne peut être utilisé que comme contrainte générique car il a des exigences de type Self ou associé
Comment êtes-vous censé résoudre ceci:
protocol SomeProtocol: Equatable {
func bla()
}
class SomeClass {
var protocols = [SomeProtocol]()
func addElement(element: SomeProtocol) {
self.protocols.append(element)
}
func removeElement(element: SomeProtocol) {
if let index = find(self.protocols, element) {
self.protocols.removeAtIndex(index)
}
}
}
Réponses:
Vous avez rencontré une variante d'un problème avec les protocoles dans Swift pour lequel aucune bonne solution n'existe encore.
Voir aussi Extension du tableau pour vérifier s'il est trié dans Swift? , il contient des suggestions sur la façon de contourner ce problème qui peuvent convenir à votre problème spécifique (votre question est très générique, vous pouvez peut-être trouver une solution de contournement en utilisant ces réponses).
la source
Vous voulez créer une classe générique, avec une contrainte de type qui nécessite que les classes utilisées avec elle soient conformes
SomeProtocol
, comme ceci:la source
SomeProtocol
-let protocolGroup: SomeClass<MyMemberClass> = SomeClass()
MyMemberClass
au tableau?let foo = SomeClass<MyMemberClass>()
Equatable
conformité - sans cela, vous pouvez utiliser votre code exact. Peut-être déposer une demande de bogue / fonctionnalité?Dans Swift, il existe une classe spéciale de protocoles qui ne fournit pas de polymorphisme sur les types qui l'implémentent. Ces protocoles utilisent des mots
Self
-associatedtype
clés ou dans leurs définitions (etEquatable
est l'un d'entre eux).Dans certains cas, il est possible d'utiliser un wrapper effacé pour rendre votre collection homomorphe. Voici un exemple.
la source
La solution limitée que j'ai trouvée est de marquer le protocole comme un protocole de classe uniquement. Cela vous permettra de comparer des objets en utilisant l'opérateur '==='. Je comprends que cela ne fonctionnera pas pour les structures, etc., mais c'était assez bon dans mon cas.
la source
protocols
, siaddElement
est appelé plus d'une fois avec le même objet?removeElement()
avant d'ajouter le nouvel élément si vous souhaitez éviter les doublons.La solution est assez simple:
la source
Equatable
protocole. Cela fait une énorme différence.SomeProtocol
dans un tableau typé.Equatable
la conformité n'est requise que pour supprimer des éléments du tableau. Ma solution est une version améliorée de la solution @almas car elle peut être utilisée avec n'importe quel type Swift conforme auEquatable
protocole.Je suppose que votre objectif principal est de conserver une collection d'objets conformes à un protocole, d'ajouter à cette collection et de la supprimer. Il s'agit de la fonctionnalité indiquée dans votre client, "SomeClass". L'héritage équatable nécessite self et cela n'est pas nécessaire pour cette fonctionnalité. Nous aurions pu faire ce travail dans des tableaux dans Obj-C en utilisant la fonction "index" qui peut prendre un comparateur personnalisé mais cela n'est pas pris en charge dans Swift. La solution la plus simple consiste donc à utiliser un dictionnaire au lieu d'un tableau comme indiqué dans le code ci-dessous. J'ai fourni getElements () qui vous rendra le tableau de protocoles que vous vouliez. Ainsi, quiconque utilisant SomeClass ne saurait même pas qu'un dictionnaire a été utilisé pour l'implémentation.
Puisque dans tous les cas, vous auriez besoin d'une propriété distinctive pour séparer vos objets, j'ai supposé que c'était "nom". Veuillez vous assurer que votre do element.name = "foo" lorsque vous créez une nouvelle instance de SomeProtocol. Si le nom n'est pas défini, vous pouvez toujours créer l'instance, mais elle ne sera pas ajoutée à la collection et addElement () renverra "false".
la source
J'ai trouvé une solution Swift pas pure et pure sur ce billet de blog: http://blog.inferis.org/blog/2015/05/27/swift-an-array-of-protocols/
L'astuce est de se conformer à
NSObjectProtocol
ce qu'il introduitisEqual()
. Par conséquent, au lieu d'utiliser leEquatable
protocole et son utilisation par défaut,==
vous pouvez écrire votre propre fonction pour trouver l'élément et le supprimer.Voici l'implémentation de votre
find(array, element) -> Int?
fonction:Remarque: Dans ce cas, vos objets conformes à
SomeProtocol
doivent hériter deNSObject
.la source