Sobes.tech
Middle

Dlaczego nie zaleca się obciążania głównego wątku w iOS i jakie są sposoby tego unikania?

sobes.tech AI

Odpowiedź od AI

Główny wątek odpowiada za aktualizację interfejsu użytkownika i obsługę zdarzeń UI. Wszelkie długotrwałe operacje (żądania sieciowe, ciężkie obliczenia, praca z plikami) na głównym wątku zablokują go, co spowoduje "zamrożony" interfejs, niską responsywność aplikacji, a nawet jej awarię (timeout watchdog).n Sposoby unikania obciążenia głównego wątku:

  1. Grand Central Dispatch (GCD): Pozwala wykonywać zadania asynchronicznie na kolejkach w tle.

    • DispatchQueue.global(): Uzyskanie globalnych kolejek w tle o różnym priorytecie.
    • DispatchQueue.main: Główna kolejka do aktualizacji UI.
    • async { ... }: Wykonanie bloku kodu asynchronicznie.
    // wykonywanie ciężkiego zadania w tle
    DispatchQueue.global(qos: .userInitiated).async {
        // ciężkie obliczenia lub żądanie sieciowe
    
        // aktualizacja UI na głównym wątku
        DispatchQueue.main.async {
            // zaktualizować interfejs użytkownika
        }
    }
    
  2. Kolejki operacji (Operation & OperationQueue): Wyższy poziom abstrakcji nad kolejkami GCD, obsługuje zależności między operacjami, anulowanie i zawieszanie.

    • OperationQueue(): Tworzenie kolejki operacji.
    • Operation: Klasa abstrakcyjna dla zadań, które można dodać do kolejki.
    • addOperation(_:): Dodanie operacji do kolejki.
    let downloadOperation = BlockOperation {
        // pobieranie danych
    }
    
    let parseOperation = BlockOperation {
        // analizowanie danych
    }
    
    // zależność: analiza zaczyna się po pobraniu
    parseOperation.addDependency(downloadOperation)
    
    let queue = OperationQueue()
    queue.addOperation(downloadOperation)
    queue.addOperation(parseOperation)
    
  3. Współbieżność (async/await): Nowoczesne podejście w Swift do programowania asynchronicznego.

    • async: Oznacza funkcję jako asynchroniczną.
    • await: Czeka na zakończenie operacji asynchronicznej.
    • Task: Tworzy nowe zadanie konkurencyjne.
    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()
                // przetwarzanie danych
                // automatyczna aktualizacja UI na głównym wątku
                // (jeśli Task jest tworzony w głównym aktorze lub DispatchQueue.main)
            } catch {
                // obsługa błędu
            }
        }
    }
    
  4. Aktorzy: Zapobiegają warunkom wyścigu podczas dostępu z różnych kontekstów konkurencyjnych, zapewniając wyłączny dostęp do swojego stanu.

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

Wybór między GCD, Kolejkami operacji i Współbieżnością zależy od złożoności zadania, wymaganego poziomu kontroli i wymagań dotyczących struktury kodu. Współbieżność jest preferowanym podejściem w nowoczesnych aplikacjach ze względu na czytelność i bezpieczeństwo.