Swift: Protokoły
Protokoły w Swift
W Swift protokoły działają w podobny sposób, jak interfejsy w innych językach programowania.
Za pomocą protokołu możesz rozszerzyć swoją klasę, strukturę lub enumerację o nowe właściwości i metody.
W przypadku klasy jest to przydatne, ponieważ klasę w Swift można dziedziczyć, tylko po jednej klasie.
Jeśli chodzi o struktury, tutaj jest większy problem. Struktury nie można rozszerzyć poprzez dziedziczenie. W tym przypadku ten problem rozwiązują protokoły.
Definicja protokołu
Protokół stworzysz za pomocą słowa kluczowego protocol:
protocol Fly {
var maximumSpeed: Int { get }
func fly()
}
Ponieważ protokół jest typem, jego nazwa musi zaczynać się od dużej litery.
W protokole umieszcza tylko się definicje właściwości i metod.
Składnia deklaracji właściwości wygląda tak:
var someProperty: Type { get set }
get i set służą do poinformowania, że dana zmienna jest tylko do: odczytu (get), zapisu (set) lub zarówno do odczytu jak i zapisu (get set).
Jeśli oznaczysz właściwość jako get i set:
protocol Fly {
var maximumSpeed: Int { get set }
}
I zastosujesz ten protokół, w taki sposób, że ta właściwość będzie computed property, zostanie zgłoszony błąd:
struct Bird: Fly {
var energy: Int = 100
var maximumSpeed: Int { // Błąd!
return energy + 50
}
}
Jest tak dlatego, bo maximumSpeed zostało oznaczone jako set, a do computed property nie można przypisać wartości.
Implementacja protokołu
Zastosowanie protokołu wygląda tak samo, jak dziedziczenie:
class Bird: Fly {
var maximumSpeed: Int = 50
func fly() {
print("Bird is flying with maximum speed: \(maximumSpeed)")
}
}
class Plane: Fly {
var maximumSpeed: Int = 1000
func fly() {
print("Plane is flying with maximum speed: \(maximumSpeed)")
}
}
var bird = Bird()
bird.fly() // Bird is flying with maximum speed: 50
var plane = Plane()
plane.fly() // Plane is flying with maximum speed: 1000
Wiele protokołów
Swift pozwalana na zastosowanie wielu protokołów:
protocol Fly {
func fly()
}
protocol Eat {
func eat()
}
class Bird: Fly, Eat {
func fly() {
print("Bird is flying")
}
func eat() {
print("Bird is eating")
}
}
var bird = Bird()
bird.fly() // Bird is flying
bird.eat() // Bird is eating
Dziedziczenie protokołów
Możesz także dziedziczyć po... innym protokole:
protocol A {
func doA()
}
protocol SomeProtocol: A {
func doSomething()
}
class MyClass: SomeProtocol {
func doA() {
print("Call doA")
}
func doSomething() {
print("Call doSomething")
}
}
Istnieje możliwość dziedziczenia po wielu protokołach:
protocol A {
func doA()
}
protocol SomeProtocol: A {
func doSomething()
}
class MyClass: SomeProtocol {
func doA() {
print("Call doA")
}
func doSomething() {
print("Call doSomething")
}
}
Struktury i protokoły
Jeśli zamierzasz zastosować protokół do struktury, a ten posiada metodę, której implementacja w strukturze będzie działać na zasadzie zmiany stanu struktury, musisz użyć dla tej metody słowa kluczowego mutating.
Przykład:
protocol Counter {
var counter: Int { get }
mutating func increment()
mutating func decrement()
}
struct MyCounter: Counter {
var counter = 0
mutating func increment() {
counter += 1
}
mutating func decrement() {
counter -= 1
}
}
var myCounter = MyCounter()
myCounter.increment()
myCounter.increment()
myCounter.decrement()
print("Counter: \(myCounter.counter)")