14. diel - Ošetrovanie chýb vo Swift
V predchádzajúcom cvičení, Riešené úlohy k 10.-13. lekciu OOP vo Swift, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
V minulej lekcii, Riešené úlohy k 10.-13. lekciu OOP vo Swift , sme sa zaoberali preťažovaním operátorov a ukázali sme si niekoľko ďalších vychytávok Swiftu. V dnešnom Swift tutoriálu si vysvetlíme poslednú dôležitú tému, než prejdeme na formulárové aplikácie. Touto témou sú chyby. Keďže je vo formulárových aplikáciách budeme stretávať, naučíme sa je dnes ošetrovať.
Chyby
Pri programovaní sa pravidelne objavujú chyby, ako ste si už určite stihli všimnúť Niektoré vzniknú našej chybou, proti vzniku iným sa môžeme len ťažko brániť. Typickým príkladom môže byť čítanie dát zo súboru alebo napríklad webové služby, ktorá zrovna nemusí byť dostupná (pretože iný programátor urobil chybu), nefunguje internet a tak podobne.
V tomto tutoriále si ukážeme, ako sa s problémami za behu programu vysporiadať tak, aby celý nespadol.
Swift podobne ako ďalšie moderné jazyky, používa koncept tzv. Výnimiek, ktoré označujú chybový stav aplikácie. Ak prechádzate z iného jazyka, bude vám povedomý, len sa tu termín výnimka nepoužíva a niekoľko vecí funguje trochu inak.
Spustenie nebezpečného kódu
Najskôr si ukážeme, ako sa zachovať, keď nejaký kód môže chybu
vyvolať. Swift je v tomto smere prísnejší a funkcie, ktoré môžu vyvolať
chybu, musia byť označené kľúčovým slovom throws
, ktoré sa
píše pred návratový typ. Podobné pravidlo funguje napr. Aj v Jave. S takou funkciou potom nemôžeme pracovať tak, ako sme
zvyknutí.
Ukážeme si jednoduchý príklad so zápisom do súboru. Založte si nový
Command Line Tool projekt s názvom ChybaSoubor
a do
main.swift
vložte nasledujúci kód:
// Tento kód zatím nefunguje let dokumentyUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL let souborUrl = dokumentyUrl.appendingPathComponent("info.txt")! "ITnetwork.cz je fajn web".write(to: souborUrl, atomically: true, encoding: String.Encoding.unicode)
Kód vyššie možno vyzerá hrozivo, ale o nič zložité nejde. Poďme si ho popísať.
- Prvý riadok získa od systému cestu k priečinku Dokumenty
- Druhý k ceste pripojí názov súboru, do ktorého budeme zapisovať.
- Na treťom riadku využijeme metódu na
String
u pre zápis do súboru. Zvyšné parametre rieši zamknutie súboru a kódovanie češtiny.
Tento kód nám zatiaľ ale nebude fungovať. Je to preto, že môže
vyvolať chybu keď do súboru nepôjde zapísať a my sme túto chybu nijako
neošetrili. Mechanizmus chýb je vo Swift podobný mechanizmu
Optionals
, kde sme tiež museli riešiť všetky neočakávané
stavy. Metóda write()
je v našom prípade označená kľúčovým
slovom throws
, čo znamená, že akonáhle ju použijeme, musíme
sa postarať o možnej chybové stavy.
Try
Problém vyriešime pomocou kľúčového slova try
, ktoré
napíšeme na začiatok tretieho riadku. Samotné ale nestačí.
Najjednoduchšie je napísať try?
, Čo je opäť veľmi
podobné Optional
konceptu. Ak sa niečo nepodarí, tak sa proste
nič nestane a program pokračuje ďalej. Keby sme try?
použili s
metódou, ktorá vracia hodnotu, tak získame Optional
, ktorý bude
v prípade chyby prázdny.
Použiť môžeme tiež try!
. Tu opäť výkričník značí
nebezpečnú situáciu a prakticky Swiftu hovoríme, že k chybe jednoducho
nemôže dôjsť a preto nechceme riešiť možné chybové stavy. Ak chyba
dôjde, tak náš program spadne.
Do-catch blok
Asi najčastejšou je doplnenie try
o blok
do-catch
. Pozri zápisnicu nižšie:
do { try "ITnetwork.cz je fajn web".write(to: souborUrl, atomically: true, encoding: String.Encoding.unicode) } catch { print("Do souboru se nepovedlo zapsat") }
Blok do
nám dovolí použiť samotné slovo try
.
Ak sa vyskytne chyba, vykoná sa blok catch
. Tu máme tiež k
dispozícii premennú error
, z ktorej môžeme získať konkrétne
chybu, ak sa niečo pokazí. Z chyby potom môžeme získať dodatočné
informácie. V ďalších lekciách si ukážeme, ako pomocou viac
catch
blokov reagovať na rôzne druhy chýb. Po vykonaní kódu
vyššie nájdete vo svojej zložke Dokumenty nový súbor s textom, ktorý sme
zapísali.
Blok defer
Blok defer
slúži na vykonanie kódu, ktorý sa má
uskutočniť po ukončení bloku, v ktorom je try
vložené. To znamená v prípade, že sa try
podarilo,
ale aj v prípade, že nám program skončil v catch
bloku pod.
Ešte než si ukážeme ako sa tento blok používa, vytvoríme z nášho
skoršieho kódu metódu. Môžeme ju nechať v súbore main.swift
.
Takéto metóde sa potom hovorí funkcie, pretože metóda patrí vždy do
nejakej triedy.
func zapisDoSouboru(text: String) { let dokumentyUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL let souborUrl = dokumentyUrl.appendingPathComponent("info.txt")! do { try text.write(to: souborUrl, atomically: true, encoding: String.Encoding.unicode) } catch { print("Do souboru se nepovedlo zapsat, protože: \(error)") } }
Aby sme nevymýšľali zbytočne zložitú ukážku, tak si napíšeme
jednoduché logovanie zavolanie našej metódy. Doplníme jej začiatok o
defer
blok:
func zapisDoSouboru(text: String) { defer { print("Provedena metoda zapisDoSouboru()") } let dokumentyUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL let souborUrl = dokumentyUrl.appendingPathComponent("info.txt")! do { try text.write(to: souborUrl, atomically: true, encoding: String.Encoding.unicode) } catch { print("Do soubor se nepovedlo zapsat, protože: \(error)") } // Zde dojde k vykonání defer bloku }
Hoci blok defer
uvádzame ako prvý, tak sa vykoná akonáhle
program opustí scope metódy (blok zložených zátvoriek), v ktorom je
defer
použité. V našom prípade teda keď sa metóda ukončí.
Tento blok sa vykoná vždy, teda keď metóda skončí
doběhnutím do jej konca, aj keď skončí tým, že niečo vráti return.
Môžeme ho používať aj napr. V cykle, kedy sa spustí po vyskočenie z cyklu
pomocou break
alebo po jeho prirodzenom dobehnutí a podobne.
Skrátka sa nemôže stať, že by sa daný kód nevyvolal. Od toho defer, čo
znamená odložiť na neskôr. Typicky sa do tohto bloku umiestňujú tzv.
Upratovacie práce ako vyčistenie pamäte a podobne, ktoré sa majú vykonať
bez ohľadu na to, či sa nebezpečná operácia podarila alebo nie. S týmto
mechanizmom sa ešte stretneme v pokročilejších kurzoch.
Teraz už vieme ako používať cudzie funkcie, ktoré môžu vyvolať chybový stav. Aj keď budeme oveľa častejšie takto spracovávať "cudzie" chyby, naučíme sa aj vyvolávať vlastné. To nás ale čaká zas nabudúce, v lekcii Enum a vlastné ERROR vo Swift .