Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 14 - Ošetřování chyb ve Swift

V předešlém cvičení, Řešené úlohy k 10.-13. lekci OOP ve Swift, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

V dnešním Swift tutoriálu si vysvětlíme poslední důležité téma, než přejdeme na formulářové aplikace. Tímto tématem jsou chyby. Jelikož je ve formulářových aplikacích budeme potkávat, naučíme se je dnes ošetřovat.

Chyby

Při programování se pravidelně objevují chyby, jak jste si již určitě stihli všimnout :) Některé vzniknou naší chybou, proti vzniku jiným se můžeme jen těžko bránit. Typickým příkladem může být čtení dat ze souboru nebo třeba webové služby, která zrovna nemusí být dostupná (protože jiný programátor udělal chybu), nefunguje internet a tak podobně.

V tomto tutoriálu si ukážeme, jak se s problémy za běhu programu vypořádat tak, aby celý nespadl.

Swift podobně jako další moderní jazyky, používá koncept tzv. výjimek, které označují chybový stav aplikace. Pokud přecházíte z jiného jazyka, bude vám povědomý, jen se zde termín výjimka nepoužívá a několik věcí funguje trochu jinak.

Spuštění nebezpečného kódu

Nejdříve si ukážeme, jak se zachovat, když nějaký kód může chybu vyvolat. Swift je v tomto směru přísnější a funkce, které mohou vyvolat chybu, musí být označeny klíčovým slovem throws, které se píše před návratový typ. Podobné pravidlo funguje např. také v Javě. S takovou funkcí poté nemůžeme pracovat tak, jak jsme zvyklí.

Ukážeme si jednoduchý příklad se zápisem do souboru. Založte si nový Command Line Tool projekt s názvem ChybaSoubor a do main.swift vložte následující 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 výše možná vypadá hrozivě, ale o nic složitého nejde. Pojďme si jej popsat.

  • První řádek získá od systému cestu ke složce Dokumenty
  • Druhý k cestě připojí název souboru, do kterého budeme zapisovat.
  • Na třetím řádku využijeme metodu na Stringu pro zápis do souboru. Zbylé parametry řeší zamknutí souboru a kódování češtiny.

Tento kód nám zatím ale nebude fungovat. Je to proto, že může vyvolat chybu když do souboru nepůjde zapsat a my jsme tuto chybu nijak neošetřili. Mechanismus chyb je ve Swift podobný mechanismu Optionals, kde jsme také museli řešit všechny neočekávané stavy. Metoda write() je v našem případě označena klíčovým slovem throws, což znamená, že jakmile ji použijeme, musíme se postarat o možné chybové stavy.

Try

Problém vyřešíme pomocí klíčového slova try, které napíšeme na začátek třetího řádku. Samotné ale nestačí.

Nejjednodušší je napsat try?, což je opět velmi podobné Optional konceptu. Pokud se něco nepovede, tak se prostě nic nestane a program pokračuje dál. Kdybychom try? použili s metodou, která vrací hodnotu, tak získáme Optional, který bude v případě chyby prázdný.

Použít můžeme také try!. Zde opět vykřičník značí nebezpečnou situaci a prakticky Swiftu říkáme, že k chybě prostě nemůže dojít a proto nechceme řešit možné chybové stavy. Pokud k chybě dojde, tak náš program spadne.

do-catch blok

Asi nejčastější je doplnění try o blok do-catch. Viz zápis níže:

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žít samotné slovo try. Pokud dojde k chybě, provede se blok catch. Zde máme rovněž k dispozici proměnnou error, ze které můžeme získat konkrétní chybu, pokud se něco pokazí. Z chyby poté můžeme získat dodatečné informace. V dalších lekcích si ukážeme, jak pomocí více catch bloků reagovat na různé druhy chyb. Po vykonání kódu výše najdete ve své složce Dokumenty nový soubor s textem, který jsme zapsali.

Blok defer

Blok defer slouží k vykonání kódu, který se má provést po ukončení bloku, ve kterém je try vložené. To znamená v případě, že se try povedlo, ale i v případě, že nám program skončil v catch bloku apod.

Ještě než si ukážeme jak se tento blok používá, vytvoříme z našeho dřívějšího kódu metodu. Můžeme ji nechat v souboru main.swift. Takové metodě se potom říká funkce, jelikož metoda patří vždy do nějaké třídy.

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

Abychom nevymýšleli zbytečně složitou ukázku, tak si napíšeme jednoduché logování zavolání naší metody. Doplníme její začátek 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
}

Ačkoliv blok defer uvádíme jako první, tak se provede jakmile program opustí scope metody (blok složených závorek), ve kterém je defer použito. V našem případě tedy když se metoda ukončí. Tento blok se vykoná vždy, tedy když metoda skončí doběhnutím do jejího konce, i když skončí tím, že něco vrátí returnem. Můžeme jej používat i např. v cyklu, kdy se spustí po vyskočení z cyklu pomocí break nebo po jeho přirozeném doběhnutí a podobně. Zkrátka se nemůže stát, že by se daný kód nevyvolal. Od toho defer, což znamená odložit na později. Typicky se do tohoto bloku umisťují tzv. úklidové práce jako vyčištění paměti a podobně, které se mají vykonat bez ohledu na to, zda se nebezpečná operace povedla či nikoli. S tímto mechanismem se ještě setkáme v pokročilejších kurzech.

Nyní již víme jak používat cizí funkce, které mohou vyvolat chybový stav.

I když budeme mnohem častěji zpracovávat "cizí" chyby, naučíme se i vyvolávat vlastní. To nás ale čeká zas příště, v lekci Enumy a vlastní Errory ve Swift.


 

Předchozí článek
Řešené úlohy k 10.-13. lekci OOP ve Swift
Všechny články v sekci
Objektově orientované programování ve Swift
Přeskočit článek
(nedoporučujeme)
Enumy a vlastní Errory ve Swift
Článek pro vás napsal Filip Němeček
Avatar
Uživatelské hodnocení:
3 hlasů
Autor se věnuje vývoji iOS aplikací (občas macOS)
Aktivity