1. 協(xié)議語法
protocol SomeProtocol {
// code
}
要讓自定義類型遵循某個協(xié)議囊卜,在類型名稱后加上協(xié)議名稱即可,中間以冒號(:
)分隔栅组,遵循多個協(xié)議時,各協(xié)議之間用逗號(刃麸、
)分隔:
struct SomeStruct: FirstProtocol, AnotherProtocol {
// code
}
擁有父類的類在遵循協(xié)議時司浪,應(yīng)該將父類名放在協(xié)議名之前,以逗號分隔:
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
// code
}
2. 屬性要求
protocol SomeProtocol {
var mustBeSettable: Int { get set } //可讀可寫的變量屬性
var doesNotNeedToBeSettable: Int { get } //可讀變量屬性
}
protocol AnotherProtocol {
static var someTypeProperty: Int { get set } //類型屬性吁伺,還可以用class關(guān)鍵字聲明
}
如下所示租谈,這是一個只含有一個實(shí)例屬性要求的協(xié)議。這個協(xié)議表示窟却,任何遵循FullyNamed
的類型,都必須有一個可讀的String
類型的實(shí)力屬性fullName
夸赫。
protocol FullyNamed {
var fullName: String { get }
}
下面是一個遵循FullyNamed
協(xié)議的簡單結(jié)構(gòu)體:
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John Higgins")
下面是一個更為復(fù)雜的類憔足,它適配并遵循了FullyNamed
協(xié)議:
class StarShip: FullyNamed {
var prefix: String?
var name: String
init(name: String, prefix: String? = nil) {
self.name = name
self.prefix = prefix
}
var fullName: String {
return (prefix != nil ? prefix! + " " : "") + name
}
}
var ncc1701 = StarShip(name: "Enterprise", prefix: "USS")
print(ncc1701.fullName)
// print "USS Enterprise"
3. 方法要求
protocol SomeProtocol {
static func someTypeMethod() // 類方法還可以用class關(guān)鍵字修飾
}
下面的例子定義了一個只含有一個實(shí)例方法的協(xié)議:
protocol RandomNumberGenerator {
func random() -> Double
}
下面的類實(shí)現(xiàn)了一個叫做線性同余生成器的偽隨機(jī)數(shù)算法:
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = (lastRandom * a + c).truncatingRemainder(dividingBy: m)
return lastRandom / m
}
}
4. Mutating
方法要求
實(shí)現(xiàn)協(xié)議中的mutating
方法時,若是類類型控妻,則不用寫mutating
關(guān)鍵字揭绑,而對于結(jié)構(gòu)體和枚舉,則必須寫mutating
關(guān)鍵字菇存。
protocol Togglable {
mutating func toggle()
}
enum OnOffSwitch: Togglable {
case Off, On
mutating func toggle() {
switch self {
case .Off:
self = .On
case .On:
self = .Off
}
}
}
var lightSwitch = OnOffSwitch.Off
lightSwitch.toggle() // On
5. 構(gòu)造器要求
protocol SomeProtocol {
init(someParameter: Int)
}
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// 構(gòu)造器實(shí)現(xiàn)部分
}
}
如果一個子類重寫了父類的指定構(gòu)造器邦蜜,并且該構(gòu)造器滿足了某個協(xié)議的要求,那么該構(gòu)造器的實(shí)現(xiàn)需要同時標(biāo)注required
和override
修飾符:
class SomeSuperClass {
init() {
// 構(gòu)造器實(shí)現(xiàn)部分
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
required override init() {
// 構(gòu)造器實(shí)現(xiàn)部分
}
}
6. 協(xié)議作為類型
class Dice {
let sides: Int
let generator: RandomNumberGenerator
init(sides: Int, generotor: RandomNumberGenerator) {
self.sides = sides
self.generator = generator
}
func roll() -> Int {
return Int(generator.random() * Double(sides)) + 1
}
}
generator
屬性的類型為RandomNumberGenerator
贱迟,因此任何遵循了RandomNumberGenerator
協(xié)議的類型的實(shí)例都可以賦值給generator
絮供,除此之外并無其他要求。
7. 委托(代理)模式
protocol SayHelloDelegate {
func sayHello(name: String)
}
class ClassA {
var delegate: SayHelloDelegate?
var name = "Lucy"
func play() {
delegate?.sayHello(name: name)
}
}
class ClassB: SayHelloDelegate {
var name = "Lily"
func sayHello(name: String) {
print("\(name) 請 \(self.name) 幫她 say Hello")
}
}
var ca = ClassA()
var cb = ClassB()
ca.delegate = cb
ca.play()
// print "Lucy 請 Lily 幫她 say Hello"
8. 協(xié)議中添加擴(kuò)展
protocol Score {
var math: Int { get set }
var english: Int { get set }
func mathPercent() -> Double
}
struct Puple: Score {
var math: Int
var english: Int
func mathPercent() -> Double {
return Double(math) / Double(math + english)
}
}
let p1 = Puple(math: 90, english: 80)
p1.mathPercent() // 0.529
extension Score {
func mathPercent() -> Double {
return Double(math) / Double(math + english)
}
}
struct CollageStudent: Score {
var math: Int
var english: Int
}
let c1 = CollageStudent(math: 80, english: 80)
c1.mathPercent() // 0.5
如此缚俏,我們可以不實(shí)現(xiàn)mathPercent
方法也能計(jì)算出數(shù)學(xué)所占分?jǐn)?shù)的比例忧换。