Sobes.tech
Middle+

Kdy byste měli používat run loop v iOS vývoji?

sobes.tech AI

Odpověď od AI

Run loop by měl být použit, když je třeba řídit chování vlákna, umožnit mu čekat na události a vykonat odpovídající kód, místo toho, aby se ihned ukončilo po dokončení své úlohy. To je kritické pro:

  1. Hlavní vlákno (Main Thread): Run loop hlavního vlákna zpracovává interakci s UIKit/AppKit, události uživatele (dotyky, kliknutí), časovače, síťové události a volání performSelector:withObject:afterDelay:. Bez něj aplikace nedokáže reagovat na akce uživatele ani aktualizovat UI.

  2. Sekundární vlákna: Když musí pracovní vlákno provádět asynchronní úkoly, poslouchat příchozí data (například sokety), zpracovávat zprávy z jiných vláken nebo používat časovače. Typické scénáře zahrnují:

    • Práci se sokety.
    • Opakované úkoly pomocí časovačů.
    • Příjem a zpracování zpráv IPC (Inter-Process Communication).
    • Udržování vlákna aktivního pro zpracování budoucích požadavků bez nutnosti jeho neustálého vytváření a ničení.

Příklad použití run loop v sekundárním vlákně může být udržování síťového spojení:

// Příklad ve Swift
class NetworkManager {
    private let networkThread = Thread {
        // Kód inicializace síťové relace, soketů atd.

        // Přidání zdroje událostí (například soketu nebo portu) do run loop
        // CFRunLoopAddSource(CFRunLoopGetCurrent(), source, CFRunLoopMode.defaultMode)

        // Přidání časovače, pokud je potřeba
        // CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.defaultMode)

        // Spuštění run loop. Zablokuje vlákno, dokud nedostane událost.
        // .distantFuture - aby run loop neskončil ihned
        RunLoop.current.run()

        // Čisticí kód po ukončení run loop
        print("Ukončení síťového vlákna")
    }

    func start() {
        // Použití `start()` místo `detachNewThreadSelector`
        // modernější přístup
        networkThread.start()
    }

    // Metoda pro zastavení run loop z jiného vlákna
    func stop() {
        // Signál run loopu, že má skončit
        // CFRunLoopStop(CFRunLoopGetCurrent()) // nebo přidání speciální události pro zpracování
        // Run loop obvykle končí, když nemá žádné zdroje událostí nebo při explicitním volání stop
    }
}

Run loop není potřeba pro vlákna, která vykonávají pouze jeden úkol a poté končí (například jednorázové operace na pozadí přes DispatchQueue.global().async). V takových případech stačí použít Grand Central Dispatch (GCD).