1、Swift入门学习笔记(第一版),对Swift的基础知识点进行梳理总结。知识点一直在变,只是作为参考,以苹果官方文档为准~
2、在学习完基本的知识点以后会结合官方文档及相关资料,在此版本的基础上进行添加更改。
二十二、协议(2)
前半部分地址:文章链接
6、委托(代理)模式
一种设计模式,允许类或结构体将一些功能委托给其他的类型的实例。
实现方法:定义封装需要被委托的方法和函数,使其遵循者拥有这些被委托的函数的方法
委托模式可以用来响应特定的动作或接受外部数据源提供的数据,无需知道外部数据源的类型信息
实际上说白点本来可以自己实现,自己不实现定义一个delegate
属性委托给其他类实现,其他类遵循协议实现这些方法
protocol GameDelegate {
func gameStart()
func gameEnd()
}
class Game {
//遵循delegate,但是是可选属性
var delegate:GameDelegate?
func startPlay() {
delegate?.gameStart()
}
func endPlay() {
delegate?.gameEnd()
}
}
//游戏跟踪类,实现delegate的三个协议。Game委托给该类实现
class GameTracker:GameDelegate {
func gameStart() {
print("Game Start")
}
func gameEnd() {
print("Game End")
}
}
let tracker = GameTracker()
let game = Game()
game.delegate = tracker
game.startPlay()
game.endPlay()
Output:
Game Start
Game End
7、扩展与协议
7.1、在扩展中添加协议成员
即便在无法修改源代码,也可通过扩展扩充已存在类型的属性,方法,下标脚本,协议等
比如A
类(不管源代码可不可获取)已遵循H
协议,但是我又想让他遵循I
协议,那么可以通过扩展来实现,A
随之添加了协议中的方法。这个与让A
类遵循协议的效果是相同的
protocol I {
//协议内容
}
extension A:I {
//实现协议内容
}
7.2、通过扩展补充协议声明
如果一个类型已经实现了协议的所有要求,但是没有声明遵循此协议,可通过扩展(空的扩展体)来补充协议声明
A
类型实现的I
协议中的所有要求,然后再用扩展去补充声明
必须要显式声明,这里不会自动转变
struct A {
//协议要求的实现
}
extension A:I {}
8、协议类型的集合
协议类型都可以在数组或字典这样的集合中使用
protocol InfoPrint {
func infoPrint()
}
class ClassA:InfoPrint {
func infoPrint() {
print("ClassA")
}
}
struct StructA:InfoPrint {
func infoPrint() {
print("StructA")
}
}
let testClassA = ClassA()
let testStructA = StructA()
//协议类型的集合
let things:[InfoPrint] = [testClassA,testStructA]
//遍历调用函数
for thing in things {
thing.infoPrint()
}
thing
是被当成InfoPrint
协议类型的,而不是ClassA
,StructA
类型。都是InfoPrint
类型,都拥有infoPrint()
方法,因此每次循环调用此方法是安全的
Output:
ClassA
StructA
9、协议的继承
协议能继承一个或多个协议,可以再继承的协议基础上增加新的内容要求
多个时用逗号隔开
10、类专属协议
添加class
关键字,限制协议只能适配到类(class
)类型,结构体或枚举不能遵循该协议
如果该协议还继承别的协议的话,class
务必写在第一位
适用场合:要求类遵循类型必须是引用语义而非值语义时(类是引用类型(指针),结构体和枚举是值类型)
11、协议合成
之前说协议可以当类型,有些场合用逗号隔开遵循多个协议就好,但是有些场合仅仅用逗号隔开容易出问题,比如当协议类型当函数的参数时。因此需要协议的合成
语法:用<>
包含要遵循的协议
注意:协议合成不是生成一个新的协议类型,而是只是将多个协议合成一个临时的协议
protocol Named {
var name:String { get }
}
protocol Aged {
var age :Int { get }
}
struct Person:Named,Aged {
var name:String
var age :Int
}
func wishHappyBirthday(celebrator:protocol<Named,Aged>) {
print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Zane", age: 22)
wishHappyBirthday(birthdayPerson)
Output:
Happy birthday Zane - you're 22!
12、检验协议的一致性
使用is
和as
操作符来检查是否遵循某一协议或强制转化为某一类型
is
:检查是否遵循某个协议
as?
:返回一个可选值,当遵循返回该协议类型;否则返回nil
as!
:强制向下转型,强转失败,会引起运行时错误
if let isObeyProtocol = birthdayPerson as? Named {
print("Yes")
} else {
print("No")
}
Output:
Yes
13、对可选协议的规定
协议有可选成员,可选择是否遵循
注意:当使用可选定义属性或方法的时候,类型会自动变为可选的,比如定义为(Int)->String
的方法会变为((Int)->String)?
可选协议调用也用可选链,因为协议可能没有实现可选内容,通过加?
来检查是否实现someOptionalMethod?(someArgument)
可选协议只能在含有@objc
前缀的协议中:此前缀表示将协议暴露给OC
代码
即使不打算跟OC
交互,想指明协议包含可选属性,可加@objc
前缀
@objc
的协议只能继承自OC
类或者其他@objc
类来遵循,不能被结构体和枚举遵循
总结起来就是:
要optional,要带@objc;
实现带@objc
的协议时,实现内容必须加上@objc
。可以加在实现的属性或方法上,也可以加在类的声明关键字的最前面,但是后者遵循类必须是NSObject的子类
类扩展里实现带有@objc的协议,只能在实现的内容上加@objc
@objc protocol OptionalProtocol {
optional var name:String {get}
}
//遵循,可选可不实现,但是一般情况下最好不要这么做
class OptionalClassA:OptionalProtocol {
}
//遵循,实现可选,加@objc
class OptionalClassB:OptionalProtocol {
@objc var name = "xxx"
}
//可选链
class OptionalClassC {
var optionalVar:OptionalProtocol?
func increment() {
if let _ = optionalVar?.name {
print("A")
} else {
print("B")
}
}
}
14、协议扩展
扩展协议为遵循者提供方法或者属性的实现!实现!实现!,这样无需每个遵循者都实现一遍,不用全局函数。如果遵循者提供了自己的实现,那么将覆盖扩展提供的默认实现
扩展协议,这样所有协议的遵循者在不用任何修改的情况下可以获得扩展所增加的方法
protocol extensionProtocol {
}
extension extensionProtocol {
var testString:String {
return "Test"
}
}
在扩展的时候可以加一些限制,只有满足这些限制的协议遵循者才能获得协议扩展提供的方法和属性
利用where
关键字写在协议后面
extension extensionProtocol where /*限制条件*/ {
//扩展内容
}