Middle+
Koks yra ryškiausias deadlock pavyzdys iOS, kurį galite pateikti?
sobes.tech AI
Atsakymas iš AI
Ryškiausias pavyzdys, kai iOS įvyksta deadlock, yra bandymas atnaujinti UI iš foninio srauto be specialių mechanizmų.
// Šis kodas sukels deadlock arba avariją (priklausomai nuo iOS versijos ir konteksto)
// iškviečiant ne iš pagrindinio srauto
DispatchQueue.global().async {
// Atliekame tam tikrą foninį darbą...
print("Fono darbas vyksta")
// Bandome tiesiogiai atnaujinti UI iš foninio srauto
// Tai sukels išimtį arba deadlock, nes UIKit nėra srautinai saugus
DispatchQueue.main.syncが必要です!
// Tai pridėta problemos demonstracijai - realiame kode to daryti negalima!
DispatchQueue.main.sync {
// Bandymas atnaujinti žymeklį pagrindiniame sraute
// Bet kadangi mes jau sinchroniškai laukiame pagrindinio srauto, kuris yra užblokuotas
// mūsų pačių sinchroninio siuntimo bloko, įvyksta deadlock.
print("Bandymas atnaujinti UI")
// someLabel.text = "Atnaujinta iš fono" // Pavyzdinė eilutė, sukelianti problemą
}
print("Fono darbas baigtas")
}
Paaiškinimas:
UIKit (rėmas, skirtas kurti naudotojo sąsają iOS) nėra srautinai saugus. Visos su UI susijusios operacijos turi būti vykdomos griežtai pagrindiniame sraute (main thread).
Aukščiau pateiktame pavyzdyje, jei iškviesite DispatchQueue.main.sync { ... } bloką iš foninio srauto, tada:
- Fono srautas bus užblokuotas ir lauks, kol pagrindinis srautas įvykdys jam perduotą bloką.
- Pagrindinis srautas gali būti užsiėmęs arba, kas yra labiau tikėtina, pats laukia, kol užbaigs tam tikrą operaciją, kuri turėjo būti pradėta iš foninio srauto (nors šiame konkrečiame pavyzdyje to nėra, sinchroninis siuntimas į pagrindinį srautą iš foninio jau yra problema).
syncatveju, foninis srautas negali užbaigti, kol pagrindinis srautas neįvykdys perduoto bloko. Jei pagrindinis srautas jau užblokuotas (pavyzdžiui, laukia, kol užbaigs foninio srauto operaciją, kuri savo ruožtu laukia pagrindinio srauto, arba tiesiog yra užsiėmęs), susidaro ciklinis laukimas, t.y., deadlock.
Teisingas sprendimas:
Naudoti asinchroninį siuntimą į pagrindinį srautą UI atnaujinimui.
// Teisingas sprendimas: UI atnaujinimas asinchroniškai pagrindiniame sraute
DispatchQueue.global().async {
// Atliekame tam tikrą foninį darbą...
print("Fono darbas vyksta")
// Siunčiame UI atnaujinimą asinchroniškai į pagrindinį srautą
DispatchQueue.main.async {
print("Atnaujiname UI pagrindiniame sraute")
// someLabel.text = "Atnaujinta iš fono" // Tinkama vieta UI atnaujinimui
}
print("Fono darbas baigtas")
}
Čia foninio srauto blokas nėra užblokuotas siunčiant jį į pagrindinį srautą, leidžiantį foniniam ir pagrindiniam srautui dirbti nepriklausomai, taip išvengiant deadlock.