Protocole Swift


Le protocole précise les méthodes et attributs nécessaires à la mise en œuvre d'une fonction spécifique.

Tout type pouvant répondre aux exigences du protocole est dit conforme au protocole.

Les classes, structures ou types d'énumération peuvent suivre le protocole et fournir des implémentations spécifiques pour compléter les méthodes et fonctions définies par le protocole.

Syntaxe

Le format de syntaxe du protocole est le suivant :

protocol SomeProtocol {
    // 协议内容
}

Pour qu'une classe suive un certain protocole, vous devez ajouter le nom du protocole après le nom du type , séparés par deux points :, dans le cadre de la définition du type. Lorsque vous suivez plusieurs protocoles, séparez-les par des virgules.

struct SomeStructure: FirstProtocol, AnotherProtocol {
    // 结构体内容
}

Si une classe a une classe parent tout en étant conforme à un protocole, le nom de la classe parent doit être placé avant le nom du protocole, séparé par des virgules.

class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
    // 类的内容
}

Spécification des attributs

Le protocole est utilisé pour spécifier des attributs d'instance spécifiques ou des attributs de classe sans préciser s'il s'agit d'attributs stockés ou d'attributs calculés. De plus, il faut préciser s'il est en lecture seule ou en lecture et écriture.

Dans le protocole, var est généralement utilisé pour déclarer les attributs d'une variable. { set get } est ajouté après la déclaration de type pour indiquer que l'attribut est lisible et les attributs en lecture seule sont représentés par { get }.

protocol classa {
    
    var marks: Int { get set }
    var result: Bool { get }
    
    func attendance() -> String
    func markssecured() -> String
    
}

protocol classb: classa {
    
    var present: Bool { get set }
    var subject: String { get set }
    var stname: String { get set }
    
}

class classc: classb {
    var marks = 96
    let result = true
    var present = false
    var subject = "Swift 协议"
    var stname = "Protocols"
    
    func attendance() -> String {
        return "The \(stname) has secured 99% attendance"
    }
    
    func markssecured() -> String {
        return "\(stname) has scored \(marks)"
    }
}

let studdet = classc()
studdet.stname = "Swift"
studdet.marks = 98
studdet.markssecured()

print(studdet.marks)
print(studdet.result)
print(studdet.present)
print(studdet.subject)
print(studdet.stname)

Le résultat de l'exécution du programme ci-dessus est :

98
true
false
Swift 协议
Swift

Provisions pour la méthode Mutating

Parfois, il est nécessaire de changer son instance dans la méthode.

Par exemple, dans une méthode d'instance d'un type valeur (structure, énumération), le mot-clé mutation est utilisé comme préfixe de la fonction et écrit avant func, indiquant que l'instance à laquelle elle appartient et son instance peut être modifié dans la méthode. La valeur de l'attribut.

protocol daysofaweek {
    mutating func show()
}

enum days: daysofaweek {
    case sun, mon, tue, wed, thurs, fri, sat
    mutating func show() {
        switch self {
        case sun:
            self = sun
            print("Sunday")
        case mon:
            self = mon
            print("Monday")
        case tue:
            self = tue
            print("Tuesday")
        case wed:
            self = wed
            print("Wednesday")
        case mon:
            self = thurs
            print("Thursday")
        case tue:
            self = fri
            print("Friday")
        case sat:
            self = sat
            print("Saturday")
        default:
            print("NO Such Day")
        }
    }
}

var res = days.wed
res.show()

Le résultat de l'exécution du programme ci-dessus est :

Wednesday

Provisions pour les constructeurs

Le protocole peut exiger que ses abonnés implémentent le constructeur spécifié.

Vous pouvez écrire la déclaration du constructeur dans la définition du protocole comme si vous écriviez un constructeur normal, mais vous n'avez pas besoin d'écrire les accolades et l'entité du constructeur. La syntaxe est la suivante : <🎜. >

protocol SomeProtocol {
   init(someParameter: Int)
}

Exemple

protocol tcpprotocol {
   init(aprot: Int)
}


Le constructeur de protocole spécifie l'implémentation dans la classe

Vous pouvez implémenter le constructeur dans la classe qui suit le protocole et le spécifier comme constructeur désigné ou la commodité du constructeur de classe. Dans les deux cas, vous devez marquer l'implémentation du constructeur avec le modificateur "required":

class SomeClass: SomeProtocol {
   required init(someParameter: Int) {
      // 构造器实现
   }
}

protocol tcpprotocol {
   init(aprot: Int)
}

class tcpClass: tcpprotocol {
   required init(aprot: Int) {
   }
}

L'utilisation du modificateur requis garantit que toutes les sous-classes qui suivent ce protocole peuvent également être utilisées comme constructeurs Spécifie de fournir une implémentation explicite ou héritée mise en œuvre.

Si une sous-classe remplace le constructeur désigné de la classe parent et que le constructeur est conforme aux dispositions d'un certain protocole, alors l'implémentation du constructeur doit être marquée avec les modificateurs requis et de remplacement :

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)")

Le résultat de l'exécution du programme ci-dessus est :

res is: 20
res is: 30
res is: 50


Type de protocole

Bien que le protocole lui-même n'implémente aucune fonction, le protocole peut être utilisé comme type.

Le protocole peut être utilisé comme d'autres types ordinaires, scénarios d'utilisation :

  • comme type de paramètre ou type de valeur de retour dans une fonction, une méthode ou un constructeur

  • En tant que type de constante, de variable ou de propriété

  • En tant que type d'élément dans un tableau, un dictionnaire ou un autre conteneur

Exemple

protocol Generator {
    typealias members
    func next() -> members?
}

var items = [10,20,30].generate()
while let x = items.next() {
    print(x)
}

for lists in [1,2,3].map( {i in i*5}) {
    print(lists)
}

print([100,200,300])
print([1,2,3].map({i in i*10}))

Le résultat de l'exécution du programme ci-dessus est :

10
20
30
5
10
15
[100, 200, 300]
[10, 20, 30]

Ajouter des membres de protocole dans les extensions

Nous pouvons étendre les types existants (classes, structures, énumérations, etc.) via des extensions.

Les extensions peuvent ajouter des attributs, des méthodes, des scripts d'indice, des protocoles et d'autres membres aux types existants.

protocol AgeClasificationProtocol {
   var age: Int { get }
   func agetype() -> String
}

class Person {
   let firstname: String
   let lastname: String
   var age: Int
   init(firstname: String, lastname: String) {
      self.firstname = firstname
      self.lastname = lastname
      self.age = 10
   }
}

extension Person : AgeClasificationProtocol {
   func fullname() -> String {
      var c: String
      c = firstname + " " + lastname
      return c
   }
   
   func agetype() -> String {
      switch age {
      case 0...2:
         return "Baby"
      case 2...12:
         return "Child"
      case 13...19:
         return "Teenager"
      case let x where x > 65:
         return "Elderly"
      default:
         return "Normal"
      }
   }
}

Héritage du protocole

Un protocole peut hériter d'un ou plusieurs autres protocoles, et de nouvelles exigences de contenu peuvent être ajoutées en fonction du protocole hérité.

La syntaxe d'héritage des protocoles est similaire à celle des classes. Plusieurs protocoles hérités sont séparés par des virgules :


protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
    // 协议定义
}

Instance

protocol Classa {
    var no1: Int { get set }
    func calc(sum: Int)
}

protocol Result {
    func print(target: Classa)
}

class Student2: Result {
    func print(target: Classa) {
        target.calc(1)
    }
}

class Classb: Result {
    func print(target: Classa) {
        target.calc(5)
    }
}

class Student: Classa {
    var no1: Int = 10
    
    func calc(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)
    }
}

var marks = Player(stmark: Student2())
var marksec = Student()

marks.print(marksec)
marks.print(marksec)
marks.print(marksec)
marks.stmark = Classb()
marks.print(marksec)
marks.print(marksec)
marks.print(marksec)

Les résultats de l'exécution du programme ci-dessus. Pour :

学生尝试 1 次通过
学生尝试 1 次通过
学生尝试 1 次通过
学生尝试 5 次通过
学生尝试 5 次通过
学生缺席考试
学生尝试 5 次通过
学生缺席考试

Protocole spécifique à la classe

Vous pouvez restreindre le protocole pour qu'il s'adapte uniquement aux types de classe en ajoutant le mot-clé class dans la liste d'héritage du protocole.

Le mot-clé class doit être le premier à apparaître dans la liste d'héritage du protocole, suivi des autres protocoles hérités. Le format est le suivant :

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // 协议定义
}

Instance

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)")

Le résultat de l'exécution du programme ci-dessus est :

res is: 20
res is: 30
res is: 50

Synthèse de protocole

Prise en charge de Swift la synthèse de plusieurs protocoles Ceci est très utile lorsque nous devons suivre plusieurs protocoles en même temps.

Le format de syntaxe est le suivant :

protocol<SomeProtocol, AnotherProtocol>

Exemple

protocol Stname {
    var name: String { get }
}

protocol Stage {
    var age: Int { get }
}

struct Person: Stname, Stage {
    var name: String
    var age: Int
}

func show(celebrator: protocol<Stname, Stage>) {
    print("\(celebrator.name) is \(celebrator.age) years old")
}

let studname = Person(name: "Priya", age: 21)
print(studname)

let stud = Person(name: "Rehan", age: 29)
print(stud)

let student = Person(name: "Roshan", age: 19)
print(student)

Le résultat de l'exécution du programme ci-dessus est :

Person(name: "Priya", age: 21)
Person(name: "Rehan", age: 29)
Person(name: "Roshan", age: 19)

Vérifiez la cohérence de le protocole

Vous pouvez utiliser les opérateurs is et as pour vérifier si un certain protocole est suivi ou une conversion forcée vers un certain type. L'opérateur

  • is est utilisé pour vérifier si une instance 遵循 possède un certain 协议.

  • as? Renvoie une valeur facultative qui renvoie le type de protocole lorsque le protocole 遵循 est instancié ; sinon, nil est renvoyé.

  • as est utilisé pour forcer la conversion vers le bas. Si la conversion forcée échoue, une erreur d'exécution se produira.

Exemple

L'exemple suivant définit un protocole HasArea, nécessitant une zone lisible de type Double :

protocol HasArea {
    var area: Double { get }
}

// 定义了Circle类,都遵循了HasArea协议
class Circle: HasArea {
    let pi = 3.1415927
    var radius: Double
    var area: Double { return pi * radius * radius }
    init(radius: Double) { self.radius = radius }
}

// 定义了Country类,都遵循了HasArea协议
class Country: HasArea {
    var area: Double
    init(area: Double) { self.area = area }
}

// Animal是一个没有实现HasArea协议的类
class Animal {
    var legs: Int
    init(legs: Int) { self.legs = legs }
}

let objects: [AnyObject] = [
    Circle(radius: 2.0),
    Country(area: 243_610),
    Animal(legs: 4)
]

for object in objects {
    // 对迭代出的每一个元素进行检查,看它是否遵循了HasArea协议
    if let objectWithArea = object as? HasArea {
        print("面积为 \(objectWithArea.area)")
    } else {
        print("没有面积")
    }
}

La sortie d'exécution du programme ci-dessus Le résultat est :

面积为 12.5663708
面积为 243610.0
没有面积