Реализация протокола вызова по умолчанию в дереве инерции - PullRequest
0 голосов
/ 07 ноября 2018

Это очень похожий вопрос: Вызов реализации протокола по умолчанию из обычного метода , НО ни один из ответов не охватывает случай, когда непереносимость играет роль . Ответ предлагает привести его к типу протокола, который решит сам, но не в этом случае (Копировать вставить на игровой площадке):

public protocol MyProtocol {
    func sayCheese()
}

public extension MyProtocol {
    func sayHi() {
        print("Hi, I am protocol")
        sayCheese()
    }

    func sayCheese() {
        print("Cheese from protocol")
    }
}

public class MyFirstClass: MyProtocol {
    public func sayCheese() {
        print("Cheese from 1")

        (self as MyProtocol).sayCheese()
    }
}

public class MySecondClass: MyFirstClass {
    override init() {
        super.init()

        sayHi()
    }

    public func sayHi() {
        print("Hi from 2")
        super.sayHi()
    }

    public override func sayCheese() {
        print("Said cheese from 2")
        super.sayCheese()
    }
}

MySecondClass()

Он печатает следующее:

...
Said cheese from 2
Cheese from 1
Said cheese from 2
Cheese from 1
...

В случае MyFirstClass, как я могу вызвать реализацию MyProtocol по умолчанию для метода sayCheese?

Редактировать: Мой вариант использования следующий: У меня есть протокол, который принят классом, который много подклассов. Протокол имеет несколько методов по умолчанию, которые могут вызывать друг друга. Некоторые из подклассов должны переопределять методы, делать вещи и вызывать super.method() (чтобы наконец вызвать реализацию протокола по умолчанию, потому что суперкласс, возможно, также переопределил реализацию протокола по умолчанию). Поэтому мне действительно нужна динамическая диспетчеризация.

1 Ответ

0 голосов
/ 08 ноября 2018

Хотя протоколы поддерживают конкретные реализации, использующие расширение, но это не соответствует концепции protocol

Протокол определяет схему методов, свойств и других требования, которые удовлетворяют конкретной задаче или функциональности.

и этого следует избегать, насколько это возможно, пока вы не будете уверены, что это не будет overriden.

Решение 1:

Если вы попали в упомянутую ситуацию, я бы предложил ввести посредника class, который ничего не делает, кроме как соответствовать этому protocol, а затем наследовать subClasses от этого class.

public class Intermediary: MyProtocol {}

public class MyFirstClass: Intermediary {
    public func sayCheese() {
        print("Cheese from 1")

        super.sayCheese()
    }
}

public class MySecondClass: MyFirstClass {
    override init() {
        super.init()

        sayHi()
    }

    public func sayHi() {
        print("Hi from 2")
        super.sayHi()
    }

    public override func sayCheese() {
        print("Said cheese from 2")
        super.sayCheese()
    }
}

Теперь создающий объект MySecondClass() напечатает вывод ниже,

Hi from 2
Hi, I am protocol
Cheese from protocol

Решение 2:

Как уже упоминалось в другом вопросе , удалите метод sayCheese из protocol, чтобы объявление протокола было пустым, но sayCheese останется в extension и прервет рекурсивный звонки на sayCheese, позволяющие вашему приложению не зависать.

public protocol MyProtocol {}
...