Lekce 11 - Protokoly (rozhraní) ve Swift
V minulé lekci, Vlastnosti ve Swift, jsme si procvičili práci s vlastnostmi.
Dnes to ve Swift tutoriálu bude opět trochu teoretické, objevíme další taje objektově orientovaného programování, uvedeme si totiž tzv. rozhraní, které Swift implementuje jako protokoly.
Rozhraní
Rozhraním objektu se myslí to, jak je objekt viditelný zvenku. Již víme,
že objekt obsahuje nějaké metody, ty mohou být privátní nebo veřejné.
Rozhraní objektu tvoří právě jeho veřejné metody, je to způsob, jakým s
určitým typem objektu můžeme komunikovat. Již jsme několikrát mohli
vidět jaké veřejné metody naše třída nabízí, např. u našeho
bojovníka do arény. Třída Bojovnik
měla následující
veřejné metody:
func utoc(souper: Bojovnik)
func branSe(uder: Int)
func nazivu() -> Bool
func nastavZpravu(zprava: String)
func vratPosledniZpravu() -> String
func grafickyZivot() -> String
Pokud si do nějaké proměnné uložíme instanci bojovníka, můžeme na ni
volat metody jako utoc()
nebo branSe()
. To pořád
není nic nového, že?
My si však rozhraní můžeme deklarovat zvlášť a to podobným způsobem jako např. třídu. Říkáme, že jsme vytvořili protokol. A tento protokol definující rozhraní poté použijeme jako datový typ.
Vše si vyzkoušíme, ale na něčem jednodušším, než je bojovník.
Vytvořme si nový projekt, konzolovou aplikaci a nazvěme ho
Protokoly
. Přidáme si nějakou jednoduchou třídu. Protože by
se dle mého názoru měla teorie vysvětlovat na něčem odlehčujícím,
vytvoříme ptáka. Bude umět pípat, dýchat a klovat. Přidejme si třídu
Ptak
, bude vypadat takto:
class Ptak { func pipni() { print("♫ ♫ ♫") } func dychej() { print("Dýchám...") } func klovni() { print("Klov, klov!") } }
Třída je opravdu triviální. Přejděme do main.swift
a
vytvořme si instanci ptáka:
let ptak = Ptak()
Nyní napíšeme ptak.
a necháme Xcode, aby nám zobrazilo
metody na třídě (lze také vyvolat stiskem Ctrl +
Space):
Vidíme, co na ptákovi můžeme vše volat. Jsou tam samozřejmě ty 3 metody, co jsme ve třídě implementovali (plus další, které mají objekty v základu).
Nyní ptákovi vytvoříme protokol. Využijeme k tomu klíčového slova
protocol
. Názvy protokolů často končí
anglickou koncovkou -able
, takže můžeme mít
Printable
, Convertible
, Renderable
apod.
Z protokolu je vlastně vidět, jakou funkcionalitu nabízí. Např.
Renderable
může znamenat, že půjde vyrenderovat, neboli
zobrazit jako součást UI.
Pro zjednodušení náš protokol pojmenujeme PtakProtokol
a
klidně ho můžeme pro zjednodušení umístit do souboru
Ptak.swift
nad třídu Ptak
. Také si definujeme
požadované metody:
protocol PtakProtokol { func pipni() func dychej() }
Modifikátor public
neuvádíme, protože protokol obsahuje
vždy pouze veřejné metody (jinak by neměl smysl, udává, jak s objektem
zvenku pracovat).
Vraťme se do main.swift
a změňme řádek s proměnnou
ptak
tak, aby již nebyla typu Ptak
, ale
PtakProtokol
:
let ptak : PtakProtokol = Ptak()
Kódem výše říkáme, že v proměnné typu PtakProtokol
očekáváme objekt, který obsahuje ty metody, co jsou v protokolu. Xcode nám
vyhubuje, protože třída Ptak
zatím protokol
PtakProtokol
neobsahuje, i když potřebné metody má, neví, že
protokol poskytuje. Přesuneme se do třídy Ptak
a nastavíme jí,
že implementuje protokol PtakProtokol
. Dělá se to stejně, jako
když třída od jiné dědí:
class Ptak: PtakProtokol { // . . .
Když se nyní vrátíme do main.swift
, řádek s proměnnou
typu PtakProtokol
je již v pořádku. Třída Ptak
korektně implementuje protokol PtakProtokol
a její instance
může být do proměnné tohoto typu uložena.
Zkusme nyní vymazat ze třídy nějakou metodu, kterou protokol udává,
např. pipni()
. Xcode nás upozorní, že implementace není
kompletní. Vraťme ji zas zpět.
Opět přidáme řádek ptak.
, Xcode nám nabídne
následující metody:
Vidíme, že na instanci můžeme nyní volat pouze metody, které poskytuje
protokol. To proto, že proměnná ptak
je již typu
PtakProtokol
, nikoli Ptak
. Metoda
klovni()
úplně chybí.
K čemu je to dobré? Výhod a využití je více, na první jsme již přišli. Pomocí protokolů dokážeme zjednodušit protokol nějakého složitého objektu a vystavit jen tu část, která se nám v tu dobu hodí.
Ještě dodám, že nemůžeme vytvořit instanci z protokolu, tento kód nebude fungovat:
// tento kód nebude fungovat let ptak : PtakProtokol = PtakProtokol()
Vícenásobná dědičnost
Swift (stejně jako většina programovacích jazyků) nepodporuje
vícenásobnou dědičnost. Nemůžeme tedy jednu třídu oddědit z několika
jiných tříd. Je to hlavně z toho důvodu, že může vyvstat problém kolize
názvů metod v různých třídách, ze kterých dědíme. Vícenásobná
dědičnost se často obchází právě přes protocol
, protože
těch můžeme ve třídě implementovat kolik chceme. Umožňuje nám to s
instancí poté pracovat určitým způsobem a vůbec nás nezajímá, jakého
typu objekt ve skutečnosti je a co všechno navíc obsahuje.
Přidejme si k projektu protocol
JesterProtokol
. Bude to protokol ještěra. Ten
bude umět také dýchat a ještě se plazit. Pro zjednodušení můžete
protokol vytvořit v aktuálním souboru Ptak.swift
nebo si
založit nový Swift soubor:
protocol JesterProtokol { func plazSe() func dychej() }
Vyzkoušejme si "vícenásobnou dědičnost", přesněji implementaci více
protokolů v jedné třídě. Udělejme si ptakoještěra. Přidejme k projektu
třídu PtakoJester.swift
. Bude implementovat protokoly
PtakProtokol
a JesterProtokol
:
class PtakoJester: PtakProtokol, JesterProtokol {
}
Když nyní klikneme v tomto kódu pravým tlačítkem na
PtakoJester
v definici třídy, můžeme v kontextovém menu zvolit
Refactor -> Add Missing Protocol Requierements a Xcode nám vygeneruje
potřebné metody, takže je stačí implementovat.
Po implementaci obou protokolů vypadá kód třídy takto,
<#code#>
je v Xcode speciální placeholder pro kód:
class PtakoJester: PtakProtokol, JesterProtokol { func pipni() { <#code#> } func dychej() { <#code#> } func plazSe() { <#code#> } func dychej() { <#code#> } }
Xcode z nějakého důvodu vygenerovalo metodu dychej()
dvakrát, pokud se vám to také stane, stačí jednu z nich smazat.
Metody doimplementujeme:
func pipni() { print("♫ ♫♫ ♫ ♫ ♫♫") } func dychej() { print("Dýchám ...") } func plazSe() { print("Plazím se...") }
A přesuňme se do main.swift
a vytvořme si instanci
ptakoještěra:
let ptakojester = PtakoJester()
Ujistěte se, že má metody z ptáka i ještěra. Mně se bohužel
zbláznilo Xcode a v nápovědě ukazovalo 3x metodu dychej()
.
Krátký výlet na Google ukázal, že to není ojedinělý problém...
Bohužel, na druhou stranu nejde o nic kritického.
V příští lekci, Přetypování a hierarchie objektů ve Swift, budeme pokračovat v podobném duchu. Protokoly ještě neopustíme a naučíme se další pokročilé techniky objektově orientovaného programování.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 11x (18.42 kB)
Aplikace je včetně zdrojových kódů v jazyce Swift