swift2 从常规方法调用协议默认实现

kzipqqlq  于 2022-11-06  发布在  Swift
关注(0)|答案(6)|浏览(177)

我在想是否有可能实现这样的事情。
我有一个这样的Playground:

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需要默认实现中的所有内容以及其他内容,该怎么办?
这在某种程度上类似于在class中调用super.方法来满足实现每个属性等的要求,但我认为不可能用structs实现同样的要求。

bfnvny8b

bfnvny8b1#

我不知道您是否还在寻找答案,但解决方法是从协议定义中删除函数,将对象转换为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"

由于某种原因,只有当函数没有被声明为协议的一部分,而是在协议的一个扩展中定义时,它才能工作。

kmpatx3s

kmpatx3s2#

你可以创建一个符合协议的嵌套类型,示例化它,然后调用它的方法(你不能访问你的类型的数据并不重要,因为协议扩展内部的实现无论如何都不能引用它),但我认为这不是一个优雅的解决方案。

struct Bar: Foo {
    func testPrint() {
        // Calling default implementation
        struct Dummy : Foo {}
        let dummy = Dummy()
        dummy.testPrint()
        print("Call from struct")
    }
}
0dxa2lsx

0dxa2lsx3#

你认为这样解决办法怎么样?

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()
olhwl3o2

olhwl3o24#

如果你把函数定义放在协议中,那么当对象被转换为协议时,它只会看到对象的函数版本,因为你是在它自己内部调用它,所以你会得到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
lf5gs5x2

lf5gs5x25#

如果您的通信协定有associatedTypeSelf需求,则转换将无法运作。若要解决这个问题,请建立一般预设实作和相容型别都可以呼叫的“阴影”预设实作。

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()
    }
}
wsewodh2

wsewodh26#

我已经想出了一个解决办法。

问题

当你在一个扩展中有一个默认的实现时,当你在另一个类/结构中实现协议时,如果你实现了方法,你就会失去这个默认的实现。这是设计的,这是协议的工作方式

溶液

  • 创建协议的默认实现,并使其成为协议的属性。
  • 然后,当您在类中实现此协议时,为默认实现提供getter
  • 在需要时调用默认实现。

示例

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"

缺点

在实现此协议的结构/类中丢失了所需的实现错误。

相关问题