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