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

时间:2018-08-07 07:34:49

标签: ios swift protocols

我有一个协议Vehicle及其扩展名,如下所示:

protocol Vehicle {
    func Drive()    
}

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

我也有如下的Stop方法声明

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

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

但是它覆盖了Stop方法

// Output
// Can Drive
// yo stop

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

4 个答案:

答案 0 :(得分:8)

嘿,我得到的答案是通过对象调用您的默认方法而不是overriddedn来遵循协议,因此我们可以根据需要调用这两种定义

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

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

答案 1 :(得分:4)

如果您需要协议扩展中声明的方法,只需使编译器认为该汽车的类型为Vehicle

let myCar = Car()
(myCar as Vehicle).Stop()

答案 2 :(得分:0)

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

我个人认为,在使用POP范式时,有可能会遇到此问题。协议扩展是在我们的代码中应用 Polymorphism 的便捷方式,但是确实会导致这种“怪异”的行为!

静态派送:

首先,请记住,它不是错误。在以下情况下:

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

有一个手动转换为honda的{​​{1}},此时编译器将使用 static dispatch 表示可以识别在编译期间应调用哪个方法(VehicleVehicle().Stop)。它为扩展中实现的Car().Stop选择默认实现,而无需检查具体类型。

动态调度:

在以下情况下

Vehicle

这里没有什么特别的,它完全按预期工作。这正是 dynamic dispatch 的含义,这导致在运行时应用 polymorphic 操作。

为更清楚起见,请考虑您使用另一种符合let myCar = Car() myCar.Drive() myCar.Stop() 协议的类型:

Vehicle

很明显,struct Bus: Vehicle { func Drive() { print("Bus Drive") } func Stop() { print("Bus stop") } } let myBus = Bus() myCar.Drive() myCar.Stop() 是将被调用的那个,实际上这是预期的!编译器“很聪明”,足以根据具体的类型(print("Bus stop"))识别要选择的方法。

此外:

为更好地了解此处发生的情况,回顾Understanding Swift Performance Apple会议可能会有所帮助。

答案 3 :(得分:0)

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

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