Подтвердить что ты не робот

Как указать, что не общий тип Swift должен соответствовать протоколу?

Я хотел бы реализовать метод Swift, который принимает определенный тип класса, но только принимает экземпляры тех классов, которые соответствуют конкретному протоколу. Например, в Objective-C у меня есть этот метод:

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

где GPUImageOutput - определенный класс, а GPUImageInput - протокол. Только классы GPUImageOutput, которые соответствуют этому протоколу, являются допустимыми входами для этого метода.

Тем не менее, автоматическая версия, сгенерированная Swift, выше

func addFilter(newFilter: GPUImageOutput!)

Это устраняет требование, согласно которому классы GPUImageOutput соответствуют протоколу GPUImageInput, что позволит пропускать несовместимые объекты (а затем сбой во время выполнения). Когда я пытаюсь определить это как GPUImageOutput<GPUImageInput>, компилятор выдает ошибку

Невозможно специализировать не общий тип "GPUImageOutput"

Как мне сделать такой класс и специализацию протокола в параметре в Swift?

4b9b3361

Ответ 1

Быстро, вы должны использовать generics, таким образом:

Учитывая эти примеры объявлений протокола, основного класса и подкласса:

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

Теперь вы хотите определить метод, который принимает входные параметры типа ATestClass (или дочернего), который соответствует протоколу ExampleProtocol. Напишите объявление метода следующим образом:

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

Ваш метод, переопределенный в swift, должен быть

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

ИЗМЕНИТЬ:

как ваш последний комментарий, пример с generics в Enum

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

Специализируется с соблюдением протокола:

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

ИЗМЕНИТЬ ^ 2:

вы можете использовать generics даже с переменными экземпляра:

Скажем, у вас есть класс и переменная экземпляра, вы хотите, чтобы эта переменная экземпляра принимала только значения типа ATestClass и соответствовала ExampleProtocol

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

Затем создайте экземпляр таким образом:

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

Если child не соответствует протоколу ExampleProtocol, он не будет компилировать

Ответ 2

этот заголовок метода из ObjC:

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

идентичен этому заголовку в Swift:

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

оба метода будут принимать один и тот же набор классов

  • который основан на классе GPUImageOutput; и
  • соответствует GPUImageInput протоколу; и
  • newFilter не является обязательным, он может быть nil;