Swift - protokoły

Protokoły zapewniają plan metod, właściwości i innych funkcji wymagań. Jest po prostu opisywany jako szkielet metod lub właściwości, a nie implementacja. Implementację metod i właściwości można ponadto przeprowadzić poprzez zdefiniowanie klas, funkcji i wyliczeń. Zgodność protokołu definiuje się jako metody lub właściwości spełniające wymagania protokołu.

Składnia

Protokoły mają również podobną składnię, jak w przypadku klas, struktur i wyliczeń -

protocol SomeProtocol {
   // protocol definition 
}

Protokoły są deklarowane po nazwie klasy, struktury lub typu wyliczenia. Możliwe są również deklaracje jednego i wielu protokołów. Jeśli zdefiniowano wiele protokołów, należy je oddzielić przecinkami.

struct SomeStructure: Protocol1, Protocol2 {
   // structure definition 
}

Gdy trzeba zdefiniować protokół dla superklasy, po nazwie protokołu należy umieścić przecinek po nazwie superklasy.

class SomeClass: SomeSuperclass, Protocol1, Protocol2 {
   // class definition 
}

Wymagania dotyczące właściwości i metod

Protokół służy do określania określonej właściwości typu klasy lub właściwości instancji. Po prostu określa sam typ lub właściwość instancji, zamiast określać, czy jest to właściwość przechowywana czy obliczana. Służy również do określenia, czy właściwość jest „gettable” czy „setable”.

Wymagania dotyczące właściwości są deklarowane przez słowo kluczowe „var” jako zmienne właściwości. {get set} służy do deklarowania gettable i ustawialnych właściwości po ich deklaracji typu. Gettable jest wymienione we właściwości {get} po ich deklaracji typu.

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 4 Protocols"
   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 4"
studdet.marks = 98
studdet.markssecured()

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

98
true
false
Swift 4 Protocols
Swift 4

Wymagania dotyczące metody mutacji

protocol daysofaweek {
   mutating func print()
}

enum days: daysofaweek {
   case sun, mon, tue, wed, thurs, fri, sat 
   mutating func print() {
      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.print()

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Wednesday

Wymagania inicjatora

Swing umożliwia użytkownikowi inicjowanie protokołów, aby były zgodne z typem, podobnie jak w przypadku zwykłych inicjatorów.

Składnia

protocol SomeProtocol {
   init(someParameter: Int)
}

Na przykład

protocol tcpprotocol {
   init(aprot: Int)
}

Implementacje klas wymagań dotyczących inicjatora protokołu

Wyznaczony lub wygodny inicjator umożliwia użytkownikowi zainicjowanie protokołu w celu dostosowania go do jego standardu przez zarezerwowane słowo kluczowe „wymagane”.

class SomeClass: SomeProtocol {
   required init(someParameter: Int) {
      // initializer implementation statements
   }
}

protocol tcpprotocol {
   init(aprot: Int)
}

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

Zgodność protokołu jest zapewniana we wszystkich podklasach w przypadku jawnej lub dziedziczonej implementacji za pomocą modyfikatora „wymagany”.

Gdy podklasa przesłania swoje wymaganie inicjalizacji superklasy, jest określana przez słowo kluczowe modyfikujące „override”.

protocol tcpprotocol {
   init(no1: Int)
}

class mainClass {
   var no1: Int        // local storage
   init(no1: Int) {
      self.no1 = no1  // initialization
   }
}

class subClass: mainClass, tcpprotocol {
   var no2: Int
   init(no1: Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
   // Requires only one parameter for convenient method
   required override convenience init(no1: Int) {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

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

Protokoły jako typy

Zamiast implementować funkcjonalności w protokole są używane jako typy dla funkcji, klas, metod itp.

Dostęp do protokołów można uzyskać jako typy w -

  • Funkcja, metoda lub inicjalizacja jako parametr lub typ zwracany

  • Stała, zmienna lub właściwość

  • Tablice, słowniki lub inne pojemniki jako elementy

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

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

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

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

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

Dodawanie zgodności protokołu z rozszerzeniem

Istniejący typ może zostać przyjęty i dostosowany do nowego protokołu przy użyciu rozszerzeń. Za pomocą rozszerzeń można dodawać nowe właściwości, metody i indeksy do istniejących typów.

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

Dziedziczenie protokołów

Swift 4 umożliwia protokołom dziedziczenie właściwości ze zdefiniowanych właściwości. Jest podobny do dziedziczenia klas, ale z możliwością wyszczególnienia wielu dziedziczonych protokołów oddzielonych przecinkami.

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(sum: 1)
   }
}
class classb: result {
   func print(target: classa) {
      target.calc(sum: 5)
   }
}

class student: classa {
   var no1: Int = 10
   
   func calc(sum: Int) {
      no1 -= sum
      print("Student attempted \(sum) times to pass")
         
      if no1 <= 0 {
         print("Student is absent for exam")
      }
   }
}

class Player {
   var stmark: result!

   init(stmark: result) {
      self.stmark = stmark
   }
   func print(target: classa) {
      stmark.print(target: target)
   }
}

var marks = Player(stmark: student2())
var marksec = student()

marks.print(target: marksec)
marks.print(target: marksec)
marks.print(target: marksec)
marks.stmark = classb()
marks.print(target: marksec)
marks.print(target: marksec)
marks.print(target: marksec)

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Student attempted 1 times to pass
Student attempted 1 times to pass
Student attempted 1 times to pass
Student attempted 5 times to pass
Student attempted 5 times to pass
Student is absent for exam
Student attempted 5 times to pass
Student is absent for exam

Protokoły tylko klasy

Gdy protokoły są zdefiniowane, a użytkownik chce zdefiniować protokół z klasami, należy go dodać, definiując najpierw klasę, a następnie listę dziedziczenia protokołów.

protocol tcpprotocol {
   init(no1: Int)
}
class mainClass {
   var no1: Int        // local storage
   init(no1: Int) {
      self.no1 = no1  // initialization
   }
}
class subClass: mainClass, tcpprotocol {
   var no2: Int
   init(no1: Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
   
   // Requires only one parameter for convenient method
   required override convenience init(no1: Int) {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

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

Skład protokołu

Swift 4 umożliwia jednoczesne wywoływanie wielu protokołów za pomocą kompozycji protokołów.

Składnia

protocol<SomeProtocol, AnotherProtocol>

Przykład

protocol stname {
   var name: String { get }
}
protocol stage {
   var age: Int { get }
}
struct Person: stname, stage {
   var name: String
   var age: Int
}
func print(celebrator: 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)

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

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

Sprawdzanie zgodności protokołu

Zgodność protokołu jest testowana za pomocą operatorów „is” i „as”, podobnie jak w przypadku rzutowania typu.

  • Operator is zwraca wartość true, jeśli instancja jest zgodna ze standardem protokołu i zwraca wartość false, jeśli się nie powiedzie.

  • Plik as? wersja operatora downcast zwraca opcjonalną wartość typu protokołu, a ta wartość jest równa nil, jeśli instancja nie jest zgodna z tym protokołem.

  • Wersja as operatora downcast wymusza downcast do typu protokołu i wyzwala błąd w czasie wykonywania, jeśli downcast nie powiedzie się.

import Foundation

@objc protocol rectangle {
   var area: Double { get }
}
@objc class Circle: rectangle {
   let pi = 3.1415927
   var radius: Double
   var area: Double { return pi * radius * radius }
   init(radius: Double) { self.radius = radius }
}
@objc class result: rectangle {
   var area: Double
   init(area: Double) { self.area = area }
}
class sides {
   var rectsides: Int
   init(rectsides: Int) { self.rectsides = rectsides }
}
let objects: [AnyObject] = [Circle(radius: 2.0),result(area:198),sides(rectsides: 4)]

for object in objects {
   if let objectWithArea = object as? rectangle {
      print("Area is \(objectWithArea.area)")
   } else {
      print("Rectangle area is not defined")
   }
}

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Area is 12.5663708
Area is 198.0
Rectangle area is not defined