Protocol is an important part of swift, similar to the interface in Java, but not quite the same. Compared with OC, swift protocol is more flexible. It can be applied in many scenarios, making the framework structure of the whole project more extensible.
I. What scenarios to use protocols
Like classes, protocols can be inherited. After inheriting a protocol, the attributes defined by the protocol are assigned and the methods in the protocol are implemented.
Since protocols are so similar to classes, why don't we implement them all with classes and why do we use protocols?
For example, there is a cat and dog. They are both pets. To achieve this, we need to do this. Define a parent class called pet. There are two methods of feeding and playing. Both cat and dog inherit the parent class of pet. This can be done naturally, but you know, cats and dogs are not pets. It's not appropriate to define pets as fathers here. It's more appropriate to define pets as agreements here.
II. The Use of the Agreement
1. Protocol Definition
// Protocol definitions are defined by Keyword protocol
protocol SomeProtocol {
// Protocol Definition
}
// A protocol may inherit one or more protocols
protocol SomeProtocol2 :SomeProtocol {
// Protocol Definition
}
// Architecture Implementation Protocol
struct SomeStructure : SomeProtocol,SomeProtocol2 {
// Definition of Structures
}
// Class implementation protocols and inheritance of parent classes, which are usually written after the parent class
class SomeSuperclass {
// Parent Class Definition
}
class SomeClass :SomeSuperclass,SomeProtocol,SomeProtocol2 {
// Subclass Definition
}
2. Attributes of protocols
The protocol does not specify whether the property should be a storage property or a computational property, it only specifies the required property name and read-write type. Attribute requirements are always declared as variable attributes, prefixed with var keyword.
protocol ClassProtocol {
static var present:Bool { get set } // Requires that the property be readable, writable, and static
var subject :String { get } // Require that this property be readable
var stname :String { get set } // Requires that this property be readable and writable
}
// Define classes to implement protocols
class MyClass :ClassProtocol {
static var present = false // If the attribute requirement of the protocol is not implemented, the error will be reported directly.
var subject = "Swift Protocols" // This property is set to be readable and writable and meets the protocol requirements.
var stname = "Class"
func attendance() -> String {
return "The \(self.stname) has secured 99% attendance"
}
func markSScured() -> String {
return "\(self.stname) has \(self.subject)"
}
}
// create object
var classa = MyClass()
print(classa.attendance()) // Results: The Class has secured 99% attendance
print(classa.markSScured()) // Results: Class has Swift Protocols
3. Implementation of protocol by common method
The protocol may require that the specified instance method and type method be implemented by the same type. These methods are written as part of the protocol definition, exactly the same as common instance and type methods, but without braces or body of methods. Variable parameters are allowed, and common methods follow the same rules, but it is not allowed to specify default values for protocol method parameters.
// Define protocols, specify method requirements
protocol RandomNumberGenerator {
func random() -> Double // To implement this protocol, we need to implement this method.
}
class LinearCongruentialGenerator :RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
// Implementing Protocol Method
func random() -> Double {
lastRandom = ((lastRandom * a + c) % m)
return lastRandom / m
}
}
let generator = LinearCongruentialGenerator()
print("random number:\(generator.random())") //Results: Random number: 0.37464991998171
print("Another random number:\(generator.random())") //Results: Another random number: 0.729023776863283
4. Implementing constructors in protocols
In SomeProtocol s, not only methods/attributes/subscripts can be declared, but constructors can also be declared. In Swift, except for some special cases, constructors are not inherited by subclasses. So although SomeClass can guarantee the definition of constructors for protocol requirements, it can not guarantee that the constructors for protocol requirements are also defined in the subclasses of SomeClass. So we need to use the required keyword when implementing the constructor required by the protocol to ensure that the SomeClass subclass must also implement the constructor.
protocol TcpProtocol {
// Initialization Constructor Requirements
init(aprot :Int)
}
class TcpClass :TcpProtocol {
var aprot: Int
// When implementing protocol initialization requirements, the required keyword must be used to ensure that subclasses must also implement this constructor
required init(aprot: Int) {
self.aprot = aprot
}
}
var tcp = TcpClass(aprot: 20)
print(tcp.aprot) // return:20
III. Examples of Use
The first examples of pet cats and dogs can be achieved by using the protocol, faming the animal's parent class, and then letting both cat and dog classes inherit the animal class. In defining a pet's attributes, there are two ways to play and feed, so that both cats and dogs can inherit the pet agreement. The implementation code is as follows:
protocol Pet {
func playWith()
func fed(food : String)
}
class Animal{
var name : String = ""
var birthPlace : String = ""
init(name: String,birthPlace:String) {
self.name = name
self.birthPlace = birthPlace
}
}
class Dog: Animal, Pet{
func playWith() {
print("The dog is playing.")
}
func fed(food: String) {
if food == "Bone" {
print("Doggy Happy")
}
else {
print("Doggy Sad")
}
}
}
class Cat: Animal, Pet {
func playWith() {
print("Cats and cats playing")
}
func fed(food: String) {
if food == "fish" {
print("Cat and cat Happy")
}
else {
print("Cat and cat Sad")
}
}
}
let dog = Dog(name:"Little Black Dog", birthPlace: "Beijing")
dog.playWith()
dog.fed(food:"Bone")
let cat = Cat(name:"Cat, Cat and White", birthPlace:"Shanghai")
cat.playWith()
cat.fed(food: "fish")
Note: When inheriting both the parent class and the protocol, the parent class should be written in front of it.
IV. The Use of Combination of Typeealias and Protocols
The function of typealias is to extend types, which collide with protocols to create different sparks.
1. Basic Use of Typeealias
extension Double {
var km : Length{ return self * 1000.0 }
var m : Length{ return self }
var cm : Length{ return self / 100 }
}
Here we extend the Double type
let runDistance:Length = 3.14.km //3140
2. Use of typealias in conjunction with protocols
Define a protocol that represents weight, but its type is defined by inheritance and its class or structure. The protocol code is as follows:
protocol WeightCalculable {
associatedtype WeightType
var weight:WeightType{get}
}
Here the weight attribute type is thrown out to facilitate the definition of the class or structure of the inheritance protocol.
class iPhone7 : WeightCalculable {
typealias WeightType = Double
var weight: WeightType {
return 0.114
}
}
class Ship : WeightCalculable {
typealias WeightType = Int
let weight: WeightType
init(weight: Int) {
self.weight = weight
}
}
There are two classes defined here, one is the iPhone 7 and the other is Ship, which are inherited from the protocol WeightCalculable, but the weight type is quite different.
The weight attribute of the iPhone 7 is Double type, and the weight attribute of Ship is Int type.
extension Int {
typealias Weight = Int
var t:Weight {
return 1_000*self
}
}
let ship = Ship(weight:4_637.t)
Finally, this code extends the Int type and customizes the t field to represent the ton
V. Use of System Protocols
We can also inherit the system protocol to define the system method. Here, we seldom introduce three common system protocols.
1. Equatable protocol is used to customize "==" to implement operations.
class Person:Equatable , Comparable, CustomStringConvertible {
var name:String
var age:Int
init(name:String,age:Int) {
self.name = name
self.age = age
}
var description: String {
return"name: "+name + ",age:" + String(age)
}
}
func == (left: Person, right: Person) ->Bool{
return left.name == right.name && left.age == right.age
}
let personA = Person(name:"a",age:9)
let personB = Person(name:"a",age:10)
personA == personB
personA != personB
Note: func = method should be written under the protocol, otherwise the compiler will make an error.
2. Comparable protocol is used to customize comparison symbols
func <(left: Person, right: Person) ->Bool{
return left.age < right.age
}
let personA = Person(name:"a",age:9)
let personB = Person(name:"a",age:10)
Note that after defining comparison symbols, many methods will be modified at the same time for our convenience, such as sorting methods.
let person1 = Person(name:"a",age:9)
let person2 = Person(name:"a",age:12)
let person3 = Person(name:"a",age:11)
var arrPerson = [person1,person2,person3]
arrPerson .sort()
//At this point arrPerson: [person 1, person 3, person 2]
3. CustomStringConvertible Protocol for Custom Printing
class Person:Equatable , Comparable, CustomStringConvertible {
var name:String
var age:Int
init(name:String,age:Int) {
self.name = name
self.age = age
}
var description: String {
return"name: "+name + ",age:" + String(age)
}
}
Rewrite the description to return the custom print format
print(person1)
//name: a,age:9
Protocols are a very important part of swift, and Apple has even come out alone for it - protocol-oriented programming. Using the advantages and flexibility of protocols, the whole project structure can be more flexible and have a more extensible architecture.