Swift中的protocol

Swift中的protocol,第1张

概述作为swift中的一种自定义类型,和struct,class,enum不同,我们使用protocol来定义某种约定,而不是一个具体的类型。这种约定通常用于表示某些类型的共性 注:本篇文章学习自泊学(boxueio.com) Protocol 定义 protocol Engine // 所有遵从Engine约定的类型都必须同时提供start和stop这两种方法。{ // -3. 属性

作为swift中的一种自定义类型,和struct,class,enum不同,我们使用protocol来定义某种约定,而不是一个具体的类型。这种约定通常用于表示某些类型的共性@H_404_3@

注:本篇文章学习自泊学(boxueio.com)@H_404_3@


@H_404_3@


@H_404_3@ Protocol

定义

@H_404_3@

protocol Engine // 所有遵从Engine约定的类型都必须同时提供start和stop这两种方法。{    // -3. 属性    var cylinder: Int { get set } // 汽缸数 //  ①    var capacity: Double {get} // 排量            // -1. 方法    func start()    func stop()        // -2. 参数://    func getname(prefix: String = "")//  ② 默认参数在protocol中是不被允许的    func getname(prefix: String)    func getname()}

注释:

① 由于Engine并不是一个具体的类型,因此当我们在一个protocol中定义具体属性的时候,我们必须使用{ get set }这样的方法来明确指定该属性支持的 *** 作。{ get set }表示可读写的,{ get }表示只读@H_404_3@

② 当protocol中的方法带有参数时,参数是不能有默认值的;如果要支持默认值,我们只能再定义两个方法@H_404_3@


@H_404_3@

应用

1)由于Engine只是一个约定,因此不能直接生成安全的对象@H_404_3@

@H_404_3@

//let truck = Engine()

@H_404_3@

     

2)只能定义一个具体类型的struct,class,enum,让它们遵从Engine的约定,如:@H_404_3@

@H_404_3@

class Truck: Engine {...}
这和类继承的方式很像,但是 当冒号:后是一个protocol时,表示类型Truck遵从protocol Engine的约束。此时会报错,这是因为,虽然我们声明了Truck遵从Engine的约定,但是我们并没有真正实现start和stop这两个方法

3)Protocol的继承@H_404_3@

除了定义属性和方法之外,protocol还可以继承的,用于表示约定A也是一个约定B,eg:
@H_404_3@

@H_404_3@

protocol TurboEngine: Engine{//    var text: Int {get}    func startTurbo()    func stopTurbo()}
let v8: TurboEngine
表示v8不仅是一个TurboEngine,也是一个Engine


@H_404_3@ 自定义类型遵从Protocol

1. 在自定义类型中实现Protocol中的方法

Protocol中的方法必须全部实现@H_404_3@

@H_404_3@

class V8: TurboEngine{    // ******** 方法约定 ********* 必须实现    // ------ Engine methods -----    func start() {        print("Engine start")    }    func stop() {        print("Engine stop")    }    func getname(prefix: String) {        print("\(prefix)-v8-engine")    }    func getname() {        print("v8-engine")    }        // ------- TurboEngine methods ------    func startTurbo() {        print("Turbo start")    }    func stopTurbo() {        print("Turbo stop")    }}


2. 在自定义类型中实现Protocol中的属性

Protocol中的属性也必须全部实现
@H_404_3@

1)Protocol中可读写的属性@H_404_3@

@H_404_3@

class V8: TurboEngine{    // ******** 属性约定 *********     var cylinder = 8}
cylinder在protocol Engine里看起来像个computed property,但是在V8的实现里可以简单定义为stored property
let v8L40 = V8()v8L40.cylinder  // getv8L40.cylinder = 18 // set. 
因此,一个stored property是满足protocol中get和set约定的


@H_404_3@

2)Protocol中只读的属性@H_404_3@

@H_404_3@

class V8: TurboEngine{        // V8实现的时候:    // 1. 可以定义一个常量 让capacity达到只读的效果;//    let capacity = 4.0 // 不是必须的    // 2. 让capacity在V8里面变成一个变量//    var capacity = 4.0    // 3. 使用computed property来实现protocol里capacity的约定。当我们使用computed property的时候,通常需要定义一个内部的stored property,eg:    private var innerCapacity = 4.0    // 然后定义一个computed property来实现capacity的约定    var capacity: Double {        get {            return self.innerCapacity        }// 尽管在protocol里面,capacity只有get属性,但是在V8的实现里同样可以给它添加set方法                set {            self.innerCapacity = newValue        }    }}
这样 当一个变量的类型是V8的时候,刚才添加的capacity就是可写的,eg:
v8L40.capacity = 8.0

但是如果把v8L40的类型转换成Engine或TurboEngine,capacity就会变成一个只读的
@H_404_3@


@H_404_3@

3. 遵从多个Protocol

在class的声明里使用 "," 将protocol分开 表示遵从多个约定
@H_404_3@

@H_404_3@

class V8: TurboEngine,Motor{...}


@H_404_3@

Protocol与Extension
1. 为Protocol添加额外的默认功能

@H_404_3@

protocol Flight{ // 航班信息    var delay: Int { get } //  航班晚点的次数    var normal: Int { get } // 航班正常的次数    var flyHour: Int { get }// 航班飞行的总时长}
1)拓展一个protocol 看似和拓展其他自定义类型没有太大的区别,

都是使用extension关键字 + 要拓展的类型名字。@H_404_3@

@H_404_3@

extension Flight { // 和定义protocol不同,我们可以在一个protocol extension中提供默认的实现,eg:在这里可以把totalTrips定义成一个computed property    var totalTrips: Int { return delay + normal }     func test ()->String{        return "test"    }}

2)尽管此时我们还没有定义任何遵从Flight的约定,但是已经可以在extension中使用Flight的数据成员了,@H_404_3@

因为swift的编译器知道,任何一个遵从Flight的自定义类型 一定会定义Flight约定的各种属性。@H_404_3@

3)定义一个表示空客A380客机的类型:@H_404_3@

@H_404_3@

struct A380: Flight { // 遵从Flight protocol    var delay: Int    // 添加Flight约定的三个属性    var normal: Int    var flyHour: Int}

4)此时,当定义了一个A380对象之后,就可以使用totalTrips获取总的飞行次数了@H_404_3@

@H_404_3@

et a380 = A380(delay: 300,normal: 700,flyHour: 3 * 365 * 24)a380.totalTripsa380.test()
playground:

@H_404_3@

     
1000"test"


@H_404_3@

2. 为已有的方法提供默认的实现

@H_404_3@

protocol Flight{ // 航班信息    var delay: Int { get } //  航班晚点的次数    var normal: Int { get } // 航班正常的次数    var flyHour: Int { get }// 航班飞行的总时长    //     eg2:    func delayRate() -> Double}
extension Flight {     var totalTrips: Int { return delay + normal }     func test ()->String{        return "test"    }        // eg2:    func delayRate() -> Double {        return Double(delay) / Double(totalTrips)    }}
a380.delayRate()

3. 1和2的区别
@H_419_439@ 通过extension添加到protocol中的内容不算做protocol的约定

1)在A380为delayRate添加一个自定义实现 ,让它返回0.1:@H_404_3@

@H_404_3@

struct A380: Flight { // 遵从Flight protocol    var delay: Int    // 添加Flight约定的三个属性    var normal: Int    var flyHour: Int        // eg3:    func delayRate() -> Double {        return 0.1    }}

@H_404_3@

a380.delayRate()(a380 as Flight).delayRate()
这时 无论flight1的类型是A380 还是Flight,delayRate的结果都会是0.1。

原因:我们在A380中重新定义了Flight中约定的方法
@H_404_3@

2)注释掉在Flight中的delayRate方法:@H_404_3@

此时再次调用:@H_404_3@

@H_404_3@ @H_267_502@a380.delayRate()(a380 as Flight).delayRate()flight1的类型是A380时,delayRate的结果是0.1;flight1的类型是Flight时,delayRate的结果是0.3。

原因:此时delayRate不再是Flight约定的一部分了,在Flight extension中的delayRate只不过是为Flight protocol提供的一个方法1的添加的额外默认功能,既然delayRate不再是Flight约定的一部分了,那么swift编译器也不会认为A380中重定义的delayRate是在重新实现Flight中的约定,而只会把A380中的delayRate当成是普通方法,因此当我们把flight1的类型转换为Flight时,swift就会调用Flight的delayRate,事实上Flight的和A380中定义的delayRate没有任何关系。
@H_404_3@


@H_404_3@

4. 为默认实现限定其可用的条件

1)同时满足两个Protocol的类型,才可实现的方法@H_404_3@

2)eg:@H_404_3@

@H_404_3@

protocol Operationallife{    var maxFlyHours: Int { get }}

3)然后使用extension来为同时满足Flight和Operationallife这两个protocol类型添加一个新的方法@H_404_3@

@H_404_3@

extension Flight where Self: Operationallife{    func isInService() -> Bool {        return self.flyHour < maxFlyHours    }}
1️⃣使用关键字where来表示额外的遵从条件
2️⃣关键字Self用来表示遵从Flight类型,要求它必须同时遵从Operationallife

4)然后让A380遵从Operationallife。@H_404_3@

@H_404_3@

extension A380: Operationallife {    var maxFlyHours: Int { return 18 * 365 * 24 }// 假定服务年限为18年}

由于在extension里我们不能定义stored property,所以只能把maxFlyHours定义成一个computed property@H_404_3@

5)此时a380就可以使用Operationallife中定义的isInService方法了@H_404_3@

@H_404_3@

a380.isInService()
总结

以上是内存溢出为你收集整理的Swift中的protocol全部内容,希望文章能够帮你解决Swift中的protocol所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1060766.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存