00. Summary of Protocols

Protocols in Swift have many special characters, So I summarize them here to make it clear.

1. Property Requirements

1.1 ‘var’ keyword always be with the properties.
Firstly, Property requirements are always declared as variable properties, prefixed with the var keyword. Gettable and settable properties are indicated by writing { get set } after their type declaration, and gettable properties are indicated by writing { get }.
1.2 ‘mutating’ keyword not be forgotten.
Secondly, If you define a protocol instance method requirement that’s intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition.

1
2
3
4
5
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
mutating func toggle()
}

2. Extension and Protocol

2.1 Extend an existing type without accessing source code.
1.1 Extend an existing type
You can extend an existing type to adopt and conform to a new protocol, even if you don’t have access to the source code for the existing type.

1
2
3
4
5
6
7
8
protocol TextRepresentable {
var textualDescription: String { get }
}
extension Dice: TextRepresentable {
var textualDescription: String {
return "A \(sides)-sided dice"
}
}

2.2 Declaring Protocol Adoption with an Extension.
If a type already conforms to all of the requirements of a protocol, but hasn’t yet stated that it adopts that protocol, you can make it adopt the protocol with an empty extension:

1
2
3
4
5
6
7
struct Hamster {
var name: String
var textualDescription: String {
return "A hamster named \(name)"
}
}
extension Hamster: TextRepresentable {}

2.3 Protocol Extensions.
Protocols can be extended directly to provide method, initializer, subscript, and computed property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function.

1
2
3
4
5
6
7
8
9
10
protocol RandomNumberGenerator {
func random() -> Double
}

extension RandomNumberGenerator {
func randomBool() -> Bool {
return random() > 0.5
}
}

Example Code Details
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
protocol RandomNumberGenerator {
func random() -> Double
}

extension RandomNumberGenerator {
func randomBool() -> Bool {
return random() > 0.5
}
}

class LinearGeneratorA: RandomNumberGenerator {
var lastRandom = 42.0
let m = 1000.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c)
.truncatingRemainder(dividingBy:m))
return lastRandom / m
}
}

class LinearGeneratorB: RandomNumberGenerator {
var lastRandom = 42.0
let m = 2000.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c)
.truncatingRemainder(dividingBy:m))
return lastRandom / m
}
}

//Verify as follows:
let generatorA = LinearGeneratorA()
print("Here's a random number A: \(generatorA.random())")
print("And here's a random Boolean A: \(generatorA.randomBool())")

let generatorB = LinearGeneratorB()
print("Here's a random number B: \(generatorB.random())")
print("And here's a random Boolean B: \(generatorB.randomBool())")
You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol.

3. Class-Only Protocols

You can limit protocol adoption to class types (and not structures or enumerations) by adding the AnyObject protocol to a protocol’s inheritance list.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protocol Generator {
}
protocol RandomNumberGenerator : LinearGeneratorA, Generator {
func random() -> Double
}
class LinearGeneratorA: RandomNumberGenerator {
var lastRandom = 42.0
let m = 1000.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c)
.truncatingRemainder(dividingBy:m))
return lastRandom / m
}
}

And It will be report errors if you try to do like as follows:

1
2
3
4
5
6
7
8
9
10
11
class LinearGeneratorB: RandomNumberGenerator {
var lastRandom = 42.0
let m = 2000.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c)
.truncatingRemainder(dividingBy:m))
return lastRandom / m
}
}

Besides, we can not limit protocol adoption to structures or enumerations types like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protocol RandomNumberGenerator : LinearGeneratorA, Generator {
func random() -> Double
}
struct LinearGeneratorA: RandomNumberGenerator {
var lastRandom = 42.0
let m = 1000.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c)
.truncatingRemainder(dividingBy:m))
return lastRandom / m
}
} // this is wrong.

Reference

[1] https://docs.swift.org/swift-book/LanguageGuide/Protocols.html
[2] https://blog.csdn.net/Forever_wj/article/details/118767086