Sobes.tech
Middle

Proč je nevhodné zatěžovat hlavní vlákno v iOS a jaké existují způsoby, jak se tomu vyhnout?

sobes.tech AI

Odpověď od AI

Hlavní vlákno je zodpovědné za aktualizaci uživatelského rozhraní a zpracování událostí UI. Jakékoli dlouhotrvající operace (síťové požadavky, náročné výpočty, práce se soubory) na hlavním vlákně jej zablokují, což povede k "zamrznutému" UI, nízké odezvě aplikace a dokonce k jejímu pádu (watchdog timeout).

Způsoby, jak se vyhnout zátěži na hlavním vlákně:

  1. Grand Central Dispatch (GCD): Umožňuje asynchronní vykonávání úloh na pozadí pomocí front.

    • DispatchQueue.global(): Získání globálních pozadíových front s různou prioritou.
    • DispatchQueue.main: Hlavní fronta pro aktualizaci UI.
    • async { ... }: Asynchronní vykonání bloku kódu.
    // vykonání náročné úlohy na pozadí
    DispatchQueue.global(qos: .userInitiated).async {
        // náročné výpočty nebo síťový požadavek
    
        // aktualizace UI na hlavním vlákně
        DispatchQueue.main.async {
            // aktualizovat uživatelské rozhraní
        }
    }
    
  2. Operation Queues (Operation & OperationQueue): Vyšší úroveň abstrakce nad GCD frontami, podporující závislosti mezi operacemi, zrušení a pozastavení.

    • OperationQueue(): Vytvoření fronty operací.
    • Operation: Abstraktní třída pro úlohy, které lze přidat do fronty.
    • addOperation(_:): Přidání operace do fronty.
    let downloadOperation = BlockOperation {
        // stáhnout data
    }
    
    let parseOperation = BlockOperation {
        // rozebrat data
    }
    
    // závislost: rozbor začíná po stažení
    parseOperation.addDependency(downloadOperation)
    
    let queue = OperationQueue()
    queue.addOperation(downloadOperation)
    queue.addOperation(parseOperation)
    
  3. Concurrency (async/await): Moderní přístup ve Swift pro asynchronní programování.

    • async: Označuje funkci jako asynchronní.
    • await: Čeká na dokončení asynchronní operace.
    • Task: Vytvoření nového konkurenčního úkolu.
    func fetchData() async throws -> Data {
        let url = URL(string: "https://example.com/data")!
        let (data, _) = try await URLSession.shared.data(from: url)
        return data
    }
    
    func updateUI() {
        Task {
            do {
                let data = try await fetchData()
                // zpracovat data
                // aktualizovat UI na hlavním vlákně automaticky
                // (pokud je Task vytvořen v hlavním Actor nebo DispatchQueue.main)
            } catch {
                // zpracovat chybu
            }
        }
    }
    
  4. Actors: Zabraňují závodům dat při přístupu z různých konkurenčních kontextů, zajišťují exkluzivní přístup ke svému stavu.

    actor DataStore {
        private var data: [String] = []
    
        func addData(_ item: String) {
            data.append(item)
        }
    
        func getData() -> [String] {
            return data
        }
    }
    
    let store = DataStore()
    
    Task {
        await store.addData("item1")
    }
    

Volba mezi GCD, Operation Queues a Concurrency závisí na složitosti úkolu, požadované úrovni kontroly a požadavcích na strukturu kódu. Concurrency je preferovaný přístup v moderních aplikacích díky čitelnosti a bezpečnosti.