Swift 协议
Posted 博BOBO
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift 协议相关的知识,希望对你有一定的参考价值。
协议的语法
- 自定义类型声明时,将协议名放在类型名的冒号之后来表示该类型采纳一个特定的协议。多个协议可以用逗号分开列出。
- 若一个类拥有父类,将这个父类名放在其采纳的协议名之前,并用逗号分隔。
protocol SomeProtocol
//定义了一个协议
protocol AnotherProtocol
//定义了一个协议
protocol OneProtocol: SomeProtocol, AnotherProtocol
//定义了一个协议 OneProtocol, 他分别遵循 SomeProtocol 和 AnotherProtocol 协议
class SomeSuperClass
//定义了一个基类
class SomeClas: SomeSuperClass, SomeProtocol, AnotherProtocol
//定义了一个类 SomeClas, 他有一个父类 SomeSuperClass, 并且他遵循了 SomeProtocol 和 AnotherProtocol 协议
属性要求
- 协议可以要求所有遵循该协议的类型提供特定名字和类型的实例属性或类型属性。协议并不会具体说明属性是储存型属性还是计算型属性——它只具体要求属性有特定的名称和类型。协议同时要求一个属性必须明确是可读的或可读的和可写的。
- 若协议要求一个属性为可读和可写的,那么该属性要求不能用常量存储属性或只读计算属性来满足。若协议只要求属性为可读的,那么任何种类的属性都能满足这个要求,而且如果你的代码需要的话,该属性也可以是可写的。
protocol SomeProtocol
var mustBeSettable: Int get set //协议要求属性必须是可写的
var doesNotNeedTobeSettable: Int get //协议要求属性可以不是可写的
protocol FullyNamed
var fullName: String get
struct Person: FullyNamed
var fullName: String
let john = Person(fullName: "John")
class StarShip: FullyNamed
var prefix: String?
var name: String
init(name: String, prefix: String? = nil)
self.name = name
self.prefix = prefix
var fullName: String // StarShip 类遵循了 FullyNamed 协议,必须要实现协议中属性的可读属性
return (prefix != nil ? prefix! + " " : "") + name
var sta = StarShip(name: "EnterPrice", prefix: "USS")
print(sta.name)
print(sta.fullName)
print(sta.prefix ?? "")
- 在协议中定义类型属性时在前面添加 static 关键字。当类的实现使用 class 或 static 关键字前缀声明类型属性要求时,这个规则仍然适用。
protocol SomeProtocol
//在协议中定义类型属性时在前面添加 static 关键字
static var someTypeProperty: Int get
class someClass: SomeProtocol
static var someTypeProperty: Int
return 3
方法要求
- 协议可以要求采纳的类型实现指定的实例方法和类方法。这些方法作为协议定义的一部分,书写方式与正常实例和类方法的方式完全相同,但是不需要大括号和方法的主体。允许变量拥有参数,与正常的方法使用同样的规则。但在协议的定义中,方法参数不能定义默认值。
- 正如类型属性要求的那样,当协议中定义类型方法时,你总要在其之前添加 static 关键字。即使在类 实现时,类型方法要求使用 class 或 static 作为关键字前缀,前面的规则仍然适用。
mutating 方法要求
- 若你定义了一个协议的实例方法需求,想要异变任何采用了该协议的类型实例,只需在协议里 方法的定义当中使用 mutating 关键字。这允许结构体和枚举类型能采用相应协议并满足方法 要求。
//枚举是值类型,在值类型的实例方法中,将mutating关键字作为函数的前缀,写在func之前,表示可以在该方法中修改它所属的实例及其实例属性的值。
enum Directions: Direction
case north, south, east, west
mutating func show()
switch self
case .north:
self = .north
print("north")
case .south:
self = .south
print("south")
case .east:
self = .east
print("east")
default:
self = .west
print("west")
var dir = Directions.east
print(dir)
初始化器要求
- 协议可以要求遵循协议的类型实现指定的初始化器。和一般的初始化器一样,只用将初始化器写在协议的定义当中,只是不用写大括号也就是初始化器的实体。
初始化器要求的类实现
-
你可以通过实现指定初始化器或便捷初始化器来使遵循该协议的类满足协议的初始化器要求。 在这两种情况下,你都必须使用 required 关键字修饰初始化器的实现。
- 如果一个子类重写了父类指定的初始化器,并且遵循协议实现了初始化器要求,那么就要为这 个初始化器的实现添加 required 和 override 两个修饰符。
protocol SomeProtocol
class SomeSuperClass
class someClass: SomeSuperClass, SomeProtocol
required override init()
protocol TcpProtocol
init(no1: Int)
func add(count: Int)
class MainClass
var no1: Int //局部变量
init(no1: Int)
self.no1 = no1 //初始化
class SubClass: MainClass, TcpProtocol
func add(count: Int)
print("lalallal")
var no2: Int
init(no1: Int, no2: Int)
self.no2 = no2
super.init(no1: no1)
// 因为遵循协议,需要加上"required"; 因为继承自父类,需要加上"override"
required override convenience init(no1: Int)
//便利构造函数 先调用本类的指定初始化器
self.init(no1: no1, no2: 0)
let res = MainClass(no1: 10)
let show = SubClass(no1: 20, no2: 30)
print("res is: \\(res.no1)") // 10
print("res is: \\(show.no1)") // 20
print("res is: \\(show.no2)") // 30
将协议作为类型
- 在函数、方法或者初始化器里作为形式参数类型或者返回类型;
- 作为常量、变量或者属性的类型;
- 作为数组、字典或者其他存储器的元素的类型。
//协议类型
protocol Generator
associatedtype member
func next() -> member?
var items = [10, 20, 30].makeIterator()
while let x = items.next()
print(x)
/** 输出:
10
20
30
*/
for list in [1, 2, 3].map( i in i * 5 )
print(list)
/**
输出:
5
10
15
*/
协议继承
- 协议可以继承一个或者多个其他协议并且可以在它继承的基础之上添加更多要求。协议继承的语法与类继承的语法相似,只不过可以选择列出多个继承的协议,使用逗号分隔。
protocol InheritingProtocol: SomeProtocol, AnotherProtocol
// 协议定义
//实例
protocol Classa
var no1: Int get set
func calculate(sum: Int)
protocol Result
func print(target: Classa)
class Student: Result
func print(target: Classa)
target.calculate(sum: 1)
class Classb: Result
func print(target: Classa)
target.calculate(sum: 5)
class Student2: Classa
var no1: Int = 10
func calculate(sum: Int)
no1 -= sum
print("学生尝试 \\(sum)次通过")
if no1 <= 0
print("学生缺席考试")
class Player
var stmark: Result!
init(stmark: Result!)
self.stmark = stmark
func print(target: Classa)
stmark.print(target: target)
var marks = Player(stmark: Student())
var marksec = Student2()
marks.print(target: marksec)
marks.print(target: marksec)
marks.print(target: marksec)
marks.stmark = Classb()
marks.print(target: marksec)
marks.print(target: marksec)
marks.print(target: marksec)
/**输出结果:
学生尝试 1次通过
学生尝试 1次通过
学生尝试 1次通过
学生尝试 5次通过
学生尝试 5次通过
学生缺席考试
学生尝试 5次通过
学生缺席考试
*/
类专用的协议
- 通过添加 AnyObject 关键字到协议的继承列表,你就可以限制协议只能被类类型采纳(并且不是结构体或者枚举)。
- 可以在协议的继承列表中,通过添加class关键字,限制协议只能适配到类(class)类型。
- 该class关键字必须是第一个出现在协议的继承列表中,其后,才是其他继承协议。格式如下:
protocol SomeProtocol
protocol someClasslOnlyProtocol: AnyObject, SomeProtocol
// AnyObject 可以限制协议只能被类类型采纳
protocol tcpProtocol
init(no1: Int)
class MainClass
var no1: Int
init(no1: Int)
self.no1 = no1
class SubClass: MainClass, tcpProtocol
var no2: Int
init(no1: Int, no2: Int)
self.no2 = no2
super.init(no1: no1) //调用父类的指定初始化器
// 因为遵循协议,需要加上"required"; 因为继承自父类,需要加上"override"
required override convenience init(no1: Int)
self.init(no1: no1, no2: 0) //便捷初始化器需要先调用本类的指定初始化器
let res = MainClass(no1: 20)
let show = SubClass(no1: 30, no2: 50)
print("res is: \\(res.no1)")
print("res is: \\(show.no1)")
print("res is: \\(show.no2)")
/**
res is: 20
res is: 30
res is: 50
*/
协议组合
- 可以使用协议组合来复合多个协议到一个要求里。协议组合行为就和你定义的临时局部协议一样拥有构成中所有协议的需求。协议组合不定义任何新的协议类型。
- 协议组合使用 SomeProtocol & AnotherProtocol 的形式。你可以列举任意数量的协议,用和符号连接 ( & ),使用逗号分隔。除了协议列表,协议组合也能包含类类型,这允许你标明一个需要的父类。
//协议组合
protocol Named
var name: String get
protocol Aged
var age: Int get
struct Person: Named, Aged
var name: String
var age: Int
func WishHappyBirthday(to celebrator: Named & Aged) //使用 & 符号连接多个协议
print("Happy birthday! \\(celebrator.name), you are \\(celebrator.age)")
let person = Person(name: "zhangsan", age: 14)
WishHappyBirthday(to: person) // 打印: Happy birthday, zhangsan, you are 14
可选协议要求
- 你可以给协议定义可选要求,这些要求不需要强制遵循协议的类型实现。可选要求使用 optional 修饰符作为前缀放在协议的定义中。可选要求允许你的代码与 Objective-C 操作。 协议和可选要求必须使用 @objc 标志标记。注意 @objc 协议只能被继承自 Objective-C 类或 其他 @objc 类采纳。它们不能被结构体或者枚举采纳。
以上是关于Swift 协议的主要内容,如果未能解决你的问题,请参考以下文章