Мне интересно, можно ли добиться такого?
У меня такая площадка:
protocol Foo {
func testPrint()
}
extension Foo {
func testPrint() {
print("Protocol extension call")
}
}
struct Bar: Foo {
func testPrint() {
// Calling self or super go call default implementation
self.testPrint()
print("Call from struct")
}
}
let sth = Bar()
sth.testPrint()
Я могу предоставить реализацию по умолчанию, extension
но что, если Bar
потребуется все, что есть в реализации по умолчанию, плюс дополнительные вещи?
Это чем-то похоже на вызов super.
методов в class
es для выполнения требования реализации каждого свойства и т.д., но я не вижу возможности добиться того же с помощью structs
.
Foo.testPrint(self)()
- проблема в том, что он не работает из-за ошибки сегментации (проверено как на 7.0 GM, так и на бета-версии 7.1)Ответы:
Я не знаю, ищете ли вы все еще ответ на этот вопрос, но способ сделать это - удалить функцию из определения протокола, привести свой объект к нему
Foo
и затем вызвать для него метод:protocol Foo { // func testPrint() <- comment this out or remove it } extension Foo { func testPrint() { print("Protocol extension call") } } struct Bar: Foo { func testPrint() { print("Call from struct") (self as Foo).testPrint() // <- cast to Foo and you'll get the default // function defined in the extension } } Bar().testPrint() // Output: "Call from struct" // "Protocol extension call"
По какой-то причине он работает только в том случае, если функция не объявлена как часть протокола, а определена в расширении протокола. Иди разбери. Но это работает.
источник
Foo
протокол не наследуется ни от одного другого протокола.Что ж, вы можете создать вложенный тип, соответствующий протоколу, создать его экземпляр и вызвать метод для этого типа (не имеет значения, что вы не можете получить доступ к данным своего типа, поскольку реализация внутри расширения протокола не может ссылаться на него в любом случае). Но это решение нельзя назвать элегантным.
struct Bar: Foo { func testPrint() { // Calling default implementation struct Dummy : Foo {} let dummy = Dummy() dummy.testPrint() print("Call from struct") } }
источник
Спасибо за сообщение! Если вы поместите определение функции в протокол, тогда, когда объект приведен как протокол, он видит только версию функции объекта, и поскольку вы вызываете ее внутри себя, вы получаете новый адрес Apple ...
Я пробовал такую версию:
import UIKit protocol MyProc { } protocol MyFuncProc { func myFunc() } extension MyProc { func myFunc() { print("Extension Version") } } struct MyStruct: MyProc, MyFuncProc { func myFunc() { print("Structure Version") (self as MyProc).myFunc() } } (MyStruct() as MyFuncProc).myFunc()
Это дает результат:
Structure Version Extension Version
источник
В случае , если ваш протокол имеет
associatedType
илиSelf
требования, то приведение не будет работать. Чтобы обойти это, создайте «теневую» реализацию по умолчанию, которую может вызывать как обычная реализация по умолчанию, так и соответствующий тип.protocol Foo { associatedType Bar } extension Foo { func testPrint() { defaultTestPrint() } } fileprivate extension Foo { // keep this as private as possible func defaultTestPrint() { // default implementation } } struct Bar: Foo { func testPrint() { // specialized implementation defaultTestPrint() } }
источник
defaultXX()
намного выразительнее и читабельнее, чем другие ответы.что вы думаете о таком способе исправить это?
protocol Foo { func testPrint() } extension Foo { func testPrint() { defaultTestPrint() } func defaultTestPrint() { print("Protocol extension call") } } struct Bar: Foo { func testPrint() { // Calling self or super go call default implementation defaultTestPrint() print("Call from struct") } } let sth = Bar() sth.testPrint()
источник
Я нашел решение для этого.
Проблема
Когда у вас есть реализация по умолчанию в расширении, когда вы реализуете протокол для другого класса / структуры, вы теряете эту реализацию по умолчанию, если реализуете метод. Это задумано, так работают протоколы
Решение
пример
protocol Foo { var defaultImplementation: DefaultImpl? { get } func testPrint() } extension Foo { // Add default implementation var defaultImplementation: DefaultImpl? { get { return nil } } } struct DefaultImpl: Foo { func testPrint() { print("Foo") } } extension Foo { func testPrint() { defaultImplementation?.testPrint() } } struct Bar: Foo { var defaultImplementation: DefaultImpl? { get { return DefaultImpl() } } func testPrint() { if someCondition { defaultImplementation?.testPrint() // Prints "Foo" } } } struct Baz: Foo { func testPrint() { print("Baz") } } let bar = Bar() bar.testPrint() // prints "Foo" let baz = Baz() baz.testPrint() // prints "Baz"
Недостатки
Вы теряете требуемую ошибку реализации в структуре / классе, где вы реализуете этот протокол.
источник