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
protocolSomeProtocol { var mustBeSettable: Int { getset } var doesNotNeedToBeSettable: Int { get } mutatingfunctoggle() }
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
protocolTextRepresentable { var textualDescription: String { get } } extensionDice: 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
structHamster { var name: String var textualDescription: String { return"A hamster named \(name)" } } extensionHamster: 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.
classLinearGeneratorA: RandomNumberGenerator { var lastRandom =42.0 let m =1000.0 let a =3877.0 let c =29573.0 funcrandom() -> Double { lastRandom = ((lastRandom * a + c) .truncatingRemainder(dividingBy:m)) return lastRandom / m } }
classLinearGeneratorB: RandomNumberGenerator { var lastRandom =42.0 let m =2000.0 let a =3877.0 let c =29573.0 funcrandom() -> 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
protocolGenerator { } protocolRandomNumberGenerator : LinearGeneratorA, Generator { funcrandom() -> Double } classLinearGeneratorA: RandomNumberGenerator { var lastRandom =42.0 let m =1000.0 let a =3877.0 let c =29573.0 funcrandom() -> 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
classLinearGeneratorB: RandomNumberGenerator { var lastRandom =42.0 let m =2000.0 let a =3877.0 let c =29573.0 funcrandom() -> 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
protocolRandomNumberGenerator : LinearGeneratorA, Generator { funcrandom() -> Double } structLinearGeneratorA: RandomNumberGenerator { var lastRandom =42.0 let m =1000.0 let a =3877.0 let c =29573.0 funcrandom() -> Double { lastRandom = ((lastRandom * a + c) .truncatingRemainder(dividingBy:m)) return lastRandom / m } } // this is wrong.