Quiero crear una clase que pueda almacenar objetos que se ajusten a un determinado protocolo. Los objetos deben almacenarse en una matriz escrita. De acuerdo con la documentación de Swift, los protocolos se pueden usar como tipos:
Debido a que es un tipo, puede usar un protocolo en muchos lugares donde se permiten otros tipos, incluidos:
- Como tipo de parámetro o tipo de retorno en una función, método o inicializador
- Como el tipo de una constante, variable o propiedad
- Como el tipo de elementos en una matriz, diccionario u otro contenedor
Sin embargo, lo siguiente genera errores de compilación:
El protocolo 'SomeProtocol' solo puede usarse como una restricción genérica porque tiene requisitos de tipo Self o asociados
¿Cómo se supone que debes resolver esto?
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)
}
}
}
Respuestas:
Has encontrado una variante de un problema con los protocolos en Swift para los cuales todavía no existe una buena solución.
Consulte también Matriz extensible para verificar si está ordenado en Swift? , contiene sugerencias sobre cómo solucionarlo que pueden ser adecuadas para su problema específico (su pregunta es muy genérica, tal vez pueda encontrar una solución usando estas respuestas).
fuente
Desea crear una clase genérica, con una restricción de tipo que requiera que las clases utilizadas con ella se ajusten
SomeProtocol
, de esta manera:fuente
SomeProtocol
-let protocolGroup: SomeClass<MyMemberClass> = SomeClass()
MyMemberClass
a la matriz?let foo = SomeClass<MyMemberClass>()
Equatable
conformidad: sin eso puede usar su código exacto. Tal vez presentar una solicitud de error / función?En Swift hay una clase especial de protocolos que no proporciona polimorfismo sobre los tipos que lo implementan. Dichos protocolos usan
Self
oassociatedtype
palabras clave en sus definiciones (yEquatable
es una de ellas).En algunos casos, es posible usar un contenedor de tipo borrado para hacer que su colección sea homomórfica. A continuación se muestra un ejemplo.
fuente
La solución limitada que encontré es marcar el protocolo como un protocolo de clase solamente. Esto le permitirá comparar objetos usando el operador '==='. Entiendo que esto no funcionará para estructuras, etc., pero fue lo suficientemente bueno en mi caso.
fuente
protocols
siaddElement
se llama más de una vez con el mismo objeto?removeElement()
antes de agregar el nuevo elemento si desea evitar duplicados.La solución es bastante simple:
fuente
Equatable
protocolo. Hace una gran diferencia.SomeProtocol
en una matriz tipada.Equatable
la conformidad se requiere solo para eliminar elementos de la matriz. Mi solución es una versión mejorada de la solución @almas porque se puede usar con cualquier tipo Swift que se ajuste alEquatable
protocolo.Supongo que su objetivo principal es mantener una colección de objetos que se ajusten a algún protocolo, agregar a esta colección y eliminarla. Esta es la funcionalidad como se indica en su cliente, "SomeClass". La herencia equitativa requiere autocontrol y eso no es necesario para esta funcionalidad. Podríamos haber hecho que esto funcione en matrices en Obj-C usando la función "índice" que puede tomar un comparador personalizado, pero esto no es compatible con Swift. Entonces, la solución más simple es usar un diccionario en lugar de una matriz como se muestra en el código a continuación. He proporcionado getElements () que le devolverá la matriz de protocolos que desea. Entonces, cualquiera que use SomeClass ni siquiera sabría que se utilizó un diccionario para la implementación.
Como en cualquier caso, necesitaría alguna propiedad distintiva para separar sus objetos, he asumido que es "nombre". Asegúrese de que su elemento do.name = "foo" cuando cree una nueva instancia de SomeProtocol. Si el nombre no está establecido, aún puede crear la instancia, pero no se agregará a la colección y addElement () devolverá "falso".
fuente
Encontré una solución Swift no pura y pura en esa publicación de blog: http://blog.inferis.org/blog/2015/05/27/swift-an-array-of-protocols/
El truco es ajustarse a
NSObjectProtocol
lo que presentaisEqual()
. Por lo tanto, en lugar de usar elEquatable
protocolo y su uso predeterminado de==
podría escribir su propia función para encontrar el elemento y eliminarlo.Aquí está la implementación de su
find(array, element) -> Int?
función:Nota: En este caso, sus objetos conformes a
SomeProtocol
deben heredar deNSObject
.fuente