How to indicate that a non-generic Swift type should conform to the protocol?

I would like to implement the Swift method, which accepts a specific type of class, but only accepts instances of those classes that correspond to a particular protocol. For example, in Objective-C, I have this method:

- (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter; 

where GPUImageOutput is a specific class, and GPUImageInput is a protocol. Only the GPUImageOutput classes that conform to this protocol are valid inputs for this method.

However, the automatic version generated by Swift is higher

 func addFilter(newFilter: GPUImageOutput!) 

This removes the requirement that the GPUImageOutput classes GPUImageOutput to the GPUImageInput protocol, which will allow incompatible objects to be skipped (and then crash at runtime). When I try to define this as GPUImageOutput<GPUImageInput> , the compiler throws an error

Cannot specialize to non-generic type "GPUImageOutput"

How do I make such a class and protocol specialization in a parameter in Swift?

+42
swift
Jun 27 '14 at 15:19
source share
2 answers

Quickly, you should use generics this way:

Given these examples of declarations of the protocol, main class, and subclass:

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

Now you want to define a method that accepts input parameters of type ATestClass (or child) that conforms to the ExampleProtocol protocol. Write a method declaration as follows:

 func addFilter<T where T: ATestClass, T: ExampleProtocol>(newFilter: T) { println(newFilter) } 

Your method overridden in swift should be

 func addFilter<T where T:GPUImageOutput, T:GPUImageInput>(newFilter:T!) { // ... } 

EDIT:

as your last comment example with generics in Enum

  enum OptionalValue<T> { case None case Some(T) } var possibleInteger: OptionalValue<Int> = .None possibleInteger = .Some(100) 

Specializes in compliance with the protocol:

  enum OptionalValue<T where T:GPUImageOutput, T:GPUImageInput> { case None case Some(T) } 

EDIT ^ 2:

you can use generics even with instance variables:

Let's say you have a class and an instance variable, you want this instance variable to accept only values ​​of type ATestClass and match ExampleProtocol

 class GiveMeAGeneric<T: ATestClass where T: ExampleProtocol> { var aGenericVar : T? } 

Then create an instance like this:

  var child = ATestClassChild() let aGen = GiveMeAGeneric<ATestClassChild>() aGen.aGenericVar = child 

If child does not comply with ExampleProtocol protocol, it will not compile

+23
Jun 27 '14 at 15:32
source share

this method header from ObjC:

 - (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter { ... } 

identical to this header in Swift:

 func addFilter<T: GPUImageOutput where T: GPUImageInput>(newFilter: T?) { ... } 

both methods will take the same set of classes

  • which is based on the GPUImageOutput class; and
  • complies with GPUImageInput protocol; and
  • newFilter is optional; it may be nil ;
+13
Jun 27 '14 at 15:48
source share



All Articles