multiple - ¿Cómo especifico que un tipo Swift no genérico debe cumplir con un protocolo?
protocolos swift (2)
Me gustaría implementar un método Swift que tome un determinado tipo de clase, pero solo tome instancias de aquellas clases que cumplan con un protocolo específico Por ejemplo, en Objective-C tengo este método:
- (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter;
donde GPUImageOutput
es una clase particular, y GPUImageInput
es un protocolo. Solo GPUImageOutput
clases GPUImageOutput
que cumplen con este protocolo son entradas aceptables para este método.
Sin embargo, la versión Swift automática generada de lo anterior es
func addFilter(newFilter: GPUImageOutput!)
Esto elimina el requisito de que GPUImageOutput
clases GPUImageOutput
cumplan con el protocolo GPUImageInput
, lo que permitirá que se pasen objetos no conformes (y luego se bloqueen en tiempo de ejecución). Cuando intento definir esto como GPUImageOutput<GPUImageInput>
, el compilador GPUImageOutput<GPUImageInput>
un error de
No se puede especializar el tipo no genérico ''GPUImageOutput''
¿Cómo haría esta clase de especialización y protocolo en un parámetro en Swift?
Es rápido debes usar genéricos, de esta manera:
Dadas estas declaraciones de ejemplo de protocolo, clase principal y subclase:
protocol ExampleProtocol {
func printTest() // classes that implements this protocol must have this method
}
// an empty test class
class ATestClass
{
}
// a child class that implements the protocol
class ATestClassChild : ATestClass, ExampleProtocol
{
func printTest()
{
println("hello")
}
}
Ahora, desea definir un método que tome parámetros de entrada de tipo ATestClass (o un elemento secundario) que cumpla con el protocolo ExampleProtocol. Escribe la declaración del método de esta manera:
func addFilter<T where T: ATestClass, T: ExampleProtocol>(newFilter: T)
{
println(newFilter)
}
Tu método, redefinido en veloz, debería ser
func addFilter<T where T:GPUImageOutput, T:GPUImageInput>(newFilter:T!)
{
// ...
}
EDITAR:
como su último comentario, un ejemplo con genéricos en un Enum
enum OptionalValue<T> {
case None
case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)
Especializado en conformidad con el protocolo:
enum OptionalValue<T where T:GPUImageOutput, T:GPUImageInput> {
case None
case Some(T)
}
EDICIÓN ^ 2:
Puedes usar genéricos incluso con variables de instancia:
Digamos que tiene una clase y una variable de instancia, desea que esta variable de instancia solo tome valores del tipo ATestClass
y que se ajuste a ExampleProtocol
class GiveMeAGeneric<T: ATestClass where T: ExampleProtocol>
{
var aGenericVar : T?
}
Luego ejemplifícalo de esta manera:
var child = ATestClassChild()
let aGen = GiveMeAGeneric<ATestClassChild>()
aGen.aGenericVar = child
Si el child
no cumple con el protocolo ExampleProtocol
, no compilará
este encabezado de método de ObjC:
- (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter { ... }
es idéntico a este encabezado en Swift :
func addFilter<T: GPUImageOutput where T: GPUImageInput>(newFilter: T?) { ... }
Ambos métodos aceptarán el mismo conjunto de clases.
- que se basa en la clase
GPUImageOutput
; y - cumple
GPUImageInput
protocoloGPUImageInput
; y - el
newFilter
es opcional, puede sernil
;