Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I specify that a non-generic Swift type should comply to a protocol?

Tags:

swift

I'd like to implement a Swift method that takes in a certain class type, but only takes instances of those classes that comply to a specific protocol. For example, in Objective-C I have this method:

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

where GPUImageOutput is a particular class, and GPUImageInput is a protocol. Only GPUImageOutput classes that comply to this protocol are acceptable inputs for this method.

However, the automatic Swift-generated version of the above is

func addFilter(newFilter: GPUImageOutput!) 

This removes the requirement that GPUImageOutput classes comply with the GPUImageInput protocol, which will allow non-compliant objects to be passed in (and then crash at runtime). When I attempt to define this as GPUImageOutput<GPUImageInput>, the compiler throws an error of

Cannot specialize non-generic type 'GPUImageOutput'

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

like image 214
Brad Larson Avatar asked Jun 27 '14 15:06

Brad Larson


People also ask

How do you declare a generic variable in Swift?

Generics allow you to declare a variable which, on execution, may be assigned to a set of types defined by us. In Swift, an array can hold data of any type. If we need an array of integers, strings, or floats, we can create one with the Swift standard library.

What's the difference between a protocol and a class in Swift?

You can create objects from classes, whereas protocols are just type definitions. Try to think of protocols as being abstract definitions, whereas classes and structs are real things you can create.

Can we make protocol only class specific struct can not adopt it?

A protocol defines a blueprint of methods, properties, and other requirements. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. But there would be a time when you want to restrict protocols to be adopted by a specific class.

What can protocols use to make them generic like?

Making a Protocol Generic. There are two ways to create a generic protocol - either by defining an abstract associatedtype or the use of Self (with a capital S). The use of Self or associatedtype is what we like to call "associated types". This is because they are only associated with the protocol they are defined in.


2 Answers

Is swift you must use generics, in this way:

Given these example declarations of 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 takes an input parameters of type ATestClass (or a child) that conforms to the protocol ExampleProtocol. Write the method declaration like this:

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

Your method, redefined in swift, should be

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

EDIT:

as your last comment, an example with generics on an Enum

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

Specialized with protocol conformance:

    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 that this instance variable takes only values of the type ATestClass and that conforms to ExampleProtocol

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

Then instantiate it in this way:

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

If child doesn't conform to the protocol ExampleProtocol, it won't compile

like image 193
LombaX Avatar answered Oct 07 '22 13:10

LombaX


this method header from ObjC:

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

is identical to this header in Swift:

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

both method will accept the same set of classes

  • which is based on GPUImageOutput class; and
  • conforms GPUImageInput protocol; and
  • the newFilter is optional, it can be nil;
like image 45
holex Avatar answered Oct 07 '22 15:10

holex