如何从 Swift 中的协议扩展覆盖实例方法?

How to override instance method from protocol extension in Swift?

我正在尝试覆盖协议扩展中的实例方法,但遇到了一些麻烦。

对于上下文,我正在制作一个包含许多不同 UICollectionView 的 iOS 应用程序。这些视图从不同的数据库获取数据(需要不同的回调函数)并且具有非常不同的布局。因为(数据库、布局)的任何组合都是可能的,所以很难在没有大量代码重复的情况下制作一个漂亮的 OOP class 层次结构。

我想到了将布局函数(主要是那些在 UICollectionViewDelegateFlowLayout 协议中定义的函数)放入协议扩展中,这样我就可以用一个扩展的协议来装饰给定的 UICollectionView subclass 以实现所有相关布局功能,但我很难过。问题的实质包含在下面的代码中。

class Base {
    func speak(){
        print("Base")
    }
}

class SubA: Base, ProtocolA {}

class SubB: Base, MyProtocolB {}

protocol MyProtocolA{
    func speak()
}

protocol MyProtocolB{
    func speak()
}

extension MyProtocolA{
    func speak(){
        print("A")        
    }
}

extension MyProtocolA{
    func speak(){
        print("B")        
    }
}

let suba = SubA()
suba.speak()  // prints "Base", I want it to print "A"

let subb = SubB()
subb.speak()  // prints "Base", I want it to print "B"

想法?

仅当符合这些协议的 class 本身未实现该方法时,才会调用协议中的默认实现。 classes 的方法会覆盖协议的默认实现,而不是相反。

通常,您会执行以下操作:

protocol MyProtocolA {
    func speak()
}

protocol MyProtocolB {
    func speak()
}

extension MyProtocolA {
    func speak() {
        print("A")        
    }
}

extension MyProtocolB {
    func speak() {
        print("B")        
    }
}

class SubA: MyProtocolA {}

class SubB: MyProtocolB {}

let suba = SubA()
suba.speak()  // prints "A"

let subb = SubB()
subb.speak()  // prints "B"

但如果你这样做

class SubC: MyProtocolA {
    func speak (){
        print("C")
    }
}

let subc = SubC()
subc.speak()  // prints "C"

坦率地说,正如您看到的那样,Base 的使用在此示例中完全多余,因此我将其删除。显然,如果您出于其他原因需要从 Base 中替换 class,请随意。但关键是协议默认实现不会覆盖 classes 的实现,而是相反。