Sobes.tech
Middle

Waarom wordt het niet aanbevolen om de hoofdthread op iOS te belasten, en welke manieren zijn er om dit te voorkomen?

sobes.tech AI

Antwoord van AI

De hoofdthread is verantwoordelijk voor het bijwerken van de gebruikersinterface en het verwerken van UI-gebeurtenissen. Elke langdurige operatie (netwerkaanvragen, zware berekeningen, werken met bestanden) op de hoofdthread zal deze blokkeren, wat zal leiden tot een "bevroren" UI, lage responsiviteit van de applicatie en zelfs een crash (watchdog timeout).

Manieren om de belasting op de hoofdthread te voorkomen:

  1. Grand Central Dispatch (GCD): Maakt het mogelijk om taken asynchroon uit te voeren op achtergrondwachtrijen.

    • DispatchQueue.global(): Toegang tot globale achtergrondwachtrijen met verschillende prioriteiten.
    • DispatchQueue.main: Hoofdwachtrij voor het bijwerken van de UI.
    • async { ... }: Voert een codeblok asynchroon uit.
    // uitvoeren van een zware taak op de achtergrond
    DispatchQueue.global(qos: .userInitiated).async {
        // zware berekeningen of netwerkverzoek
    
        // bijwerken van de UI op de hoofdthread
        DispatchQueue.main.async {
            // gebruikersinterface bijwerken
        }
    }
    
  2. Operation Queues (Operation & OperationQueue): Een hogere abstractie boven GCD-wachtrijen, ondersteunt afhankelijkheden tussen operaties, annulering en onderbreking.

    • OperationQueue(): Aanmaken van een operatiewachtrij.
    • Operation: Abstracte klasse voor taken die aan de wachtrij kunnen worden toegevoegd.
    • addOperation(_:): Toevoegen van een operatie aan de wachtrij.
    let downloadOperation = BlockOperation {
        // gegevens downloaden
    }
    
    let parseOperation = BlockOperation {
        // gegevens parseren
    }
    
    // afhankelijkheid: parsing begint na downloaden
    parseOperation.addDependency(downloadOperation)
    
    let queue = OperationQueue()
    queue.addOperation(downloadOperation)
    queue.addOperation(parseOperation)
    
  3. Concurrency (async/await): Moderne aanpak in Swift voor asynchrone programmeren.

    • async: Markeert een functie als asynchroon.
    • await: Wacht op het voltooien van een asynchrone operatie.
    • Task: Creëert een nieuwe gelijktijdige taak.
    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()
                // gegevens verwerken
                // UI automatisch bijwerken op de hoofdthread
                // (als Task wordt gemaakt in de hoofd Actor of DispatchQueue.main)
            } catch {
                // fout afhandelen
            }
        }
    }
    
  4. Actors: Voorkomen racecondities bij toegang vanuit verschillende gelijktijdige contexten, door exclusieve toegang tot hun toestand te garanderen.

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

De keuze tussen GCD, Operation Queues en Concurrency hangt af van de complexiteit van de taak, het benodigde controle niveau en de vereisten voor code-structurering. Concurrency is de voorkeursaanpak in moderne applicaties vanwege leesbaarheid en veiligheid.