Sobes.tech
Middle

Kodėl nerekomenduojama apkrauti pagrindinį srautą iOS ir kokie būdai yra to išvengti?

sobes.tech AI

Atsakymas iš AI

Pagrindinis siūlas atsakingas už naudotojo sąsajos atnaujinimą ir UI įvykių apdorojimą. Bet kokios ilgalaikės operacijos (tinklo užklausos, sunkūs skaičiavimai, darbai su failais) pagrindiniame siūle jį užblokuos, tai sukels "užšaldytą" UI, mažą reagavimą ir net programos avariją (watchdog timeout).

Kaip išvengti apkrovos pagrindiniame siūle:

  1. Grand Central Dispatch (GCD): Leidžia vykdyti užduotis asinchroniškai foninėse eilėse.

    • DispatchQueue.global(): Gauti globalias fonines eilutes su skirtingais prioritetais.
    • DispatchQueue.main: Pagrindinė eilė UI atnaujinimui.
    • async { ... }: Asinchroniškai vykdyti kodo bloką.
    // vykdyti sunkią užduotį foniniame sraute
    DispatchQueue.global(qos: .userInitiated).async {
        // sunkūs skaičiavimai arba tinklo užklausa
    
        // atnaujinti UI pagrindiniame sraute
        DispatchQueue.main.async {
            // atnaujinti naudotojo sąsają
        }
    }
    
  2. Operation Queues (Operation & OperationQueue): Aukštesnio lygio abstrakcija virš GCD eilių, palaikanti priklausomybes tarp operacijų, atšaukimą ir pauzę.

    • OperationQueue(): Sukurti operacijų eilę.
    • Operation: Abstrakti klasė užduotims, kurias galima pridėti į eilę.
    • addOperation(_:): Pridėti operaciją į eilę.
    let downloadOperation = BlockOperation {
        // atsisiųsti duomenis
    }
    
    let parseOperation = BlockOperation {
        // išanalizuoti duomenis
    }
    
    // priklausomybė: analizė prasideda po atsisiuntimo
    parseOperation.addDependency(downloadOperation)
    
    let queue = OperationQueue()
    queue.addOperation(downloadOperation)
    queue.addOperation(parseOperation)
    
  3. Concurrency (async/await): Šiuolaikinis požiūris Swift programavimui asinchroniškai.

    • async: Pažymi funkciją kaip asinchroninę.
    • await: Laukia asinchroninės operacijos pabaigos.
    • Task: Kurti naują konkurentinę užduotį.
    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()
                // apdoroti duomenis
                // UI automatiškai atnaujinama pagrindiniame sraute
                // (jei Task sukurtas pagrindiniame aktoriuje arba DispatchQueue.main)
            } catch {
                // apdoroti klaidą
            }
        }
    }
    
  4. Actors: Užkerta kelią duomenų lenktynėms prieigos metu iš skirtingų konkurentinių kontekstų, užtikrindami išskirtinę prieigą prie savo būsenos.

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

Pasirinkimas tarp GCD, Operation Queue ir Concurrency priklauso nuo užduoties sudėtingumo, reikalingo kontrolės lygio ir kodo struktūros reikalavimų. Concurrency yra pageidaujamas požiūris šiuolaikinėse programose dėl skaitomumo ir saugumo.