Letní akce! Lákají tě IT školení C#, Javy a PHP v Brně? Přihlas se a napiš nám do zpráv kód "BRNO 500" pro slevu 500 Kč na libovolný brněnský kurz. Lze kombinovat se slevami uvedenými u školení i použít pro více kurzů. Akce končí 28.7.

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

Swift OOP Ošetřování chyb ve Swift

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Přetypování a hierarchie objektů ve Swift, jsme se zabývali rozhraním. 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 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 adresu složky 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 (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 takto 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.


 

 

Článek pro vás napsal Filip Němeček
Avatar
Jak se ti líbí článek?
1 hlasů
Autor se příležitostně věnuje vývoji iOS aplikací či těch webových za pomocí frameworku Django. Aktuální projekt: hrejzdarma.cz Twitter: @nemecek_f (neprogramátorské tweety)
Aktivity (2)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!