Swift 协议和扩展,我需要根据需要调用覆盖方法或默认扩展方法

Swift protocol and extension, I need to call overridden method or default extension method as per requirement

我有一个协议 Vehicle 及其扩展如下:

protocol Vehicle {
    func Drive()    
}

extension Vehicle {
    func Stop() {
        print("iiiich...")
    }
}

我也有像下面这样的停止方法声明

struct Car: Vehicle {
    func Drive() {
        print("Can Drive")
    }
    func Stop() {
        print("yo stop")
    }
}

let myCar = Car()
myCar.Drive()
myCar.Stop()

但是它覆盖了停止方法

// Output
// Can Drive
// yo stop

并且根据我的要求,我有时需要默认方法,有时需要重写方法定义

如果需要在协议扩展中声明的方法,只需要让编译器认为汽车是Vehicle:

类型即可
let myCar = Car()
(myCar as Vehicle).Stop()

嘿,我得到的答案是通过对象调用你的默认方法而不是覆盖来符合协议,所以我们可以根据需要调用这两个定义

let honda: Vehicle = Car()
honda.Drive()
honda.Stop()
// Output
// Can Drive
// iiiich..

当我们创建一个没有类型的变量时,当对象仅符合协议时,这是静态分派。

正如答案中已经提到的,通用解决方案是确保调用 Stop() 方法的实例是 Vehicle 类型(而不是 Car)。不过我想提一下这背后的逻辑是什么。

就个人而言,我认为在使用 POP 范式时可能会遇到这个问题。协议扩展是在我们的代码中应用 多态性 的一种便捷方式,但它确实会导致这种 "weird" 行为!

静态调度:

首先,请记住它不是一个错误。如果是:

let honda: Vehicle = Car()
honda.Drive()
honda.Stop()

手动将honda转换为Vehicle,此时编译器将使用static dispatch,这意味着在编译期间可以识别应该调用哪个方法(Vehicle().StopCar().Stop)。它选择在扩展中实现的 Vehicle 的默认实现,而不需要检查具体类型是什么。

动态调度:

如果是:

let myCar = Car()
myCar.Drive()
myCar.Stop()

这里没有什么特别的,它完全符合预期。这正是 dynamic dispatch 的意思,导致应用 polymorphic 操作期间运行次。

为了更清楚,假设您有另一种类型符合 Vehicle 协议:

struct Bus: Vehicle {
    func Drive() {
        print("Bus Drive")
    }
    func Stop() {
        print("Bus stop")
    }
}

let myBus = Bus()
myCar.Drive()
myCar.Stop()

显然,print("Bus stop") 是将被调用的那个,实际上这是预期的!编译器 "smart" 足以根据具体类型 (Bus().Stop) 识别要选择的方法。

此外:

为了更好地了解这里发生的事情,查看 Understanding Swift Performance Apple 会话可能会有所帮助。

您需要一个具有默认实现的协议,该协议允许结构参数,可以执行自定义行为:

import UIKit

struct Car{
    //Any properties

    func drive(){
        print("Yo Drive")
    }
    func stop(){
        print("Yo Stop")
    }
}

protocol Vehicle {
    func drive(vehicle : Car?)
    func stop(vehicle : Car?)
}
extension Vehicle where Self: UIViewController {
    func drive(vehicle : Car? = nil) {
        if (vehicle != nil){
            vehicle?.drive()
        }else{
            print("drive default behavior")
        }
    }
    func stop(vehicle : Car? = nil) {
        if (vehicle != nil){
            vehicle?.stop()
        }else{
            print("stop default behavior")
        }
    }
}

class ViewController : UIViewController, Vehicle {

    func driving() {
        drive() //will print drive default behavior
        stop()  //will print stop default behavior
        let car = Car()
        drive(vehicle: car) //will print yo drive!
        stop(vehicle: car)  //will print yo Stop!
    }

    override func viewDidLoad() {
        driving()
    }
}