Middle+
Milline on kõige silmatorkavam deadlock näide iOS-is, mida võite tuua?
sobes.tech AI
Vastus AI-lt
Kõige silmatorkavam näide deadlockist iOS-is toimub siis, kui üritatakse UI-d värskendada taustajärjest otse ilma spetsiaalsete mehhanismideta.
// See kood põhjustab deadlocki või krahhi (sõltuvalt iOS versioonist ja kontekstist)
// kui kutsutakse väljaspool peamist järjepidevust
DispatchQueue.global().async {
// Teeme mingit taustatööd...
print("Taustatöö käib")
// Püüame otse taustajärjest uuendada UI-d
// See põhjustab erandi või deadlocki, kuna UIKit ei ole järjepidev
DispatchQueue.main.syncが必要です!
// See on lisatud probleemi demonstreerimiseks - reaalsetes koodides seda teha ei tohi!
DispatchQueue.main.sync {
// Püüd peamise järjepidevuse märgi uuendamiseks
// Kuid kuna me juba ootame sünkroonselt peamist järjepidevust, mis on blokeeritud
// meie enda sünkroonsel saatmise blokil, tekib deadlock.
print("UI uuendamise katse")
// someLabel.text = "Uuendatud taustast" // Näide, mis põhjustab probleemi
}
print("Taustatöö lõpetatud")
}
Selgitus:
UIKit ( raamistik kasutajaliidese loomiseks iOS-is) ei ole järjepidev. Kõik UI-ga seotud toimingud peavad toimuma rangelt peamisel järjepidevusel (main thread).
Kui kutsute DispatchQueue.main.sync { ... } bloki taustajärjest, siis:
- Taustajärjest blokeerub ja ootab, kuni peamine järjepidevus täidab talle saadetud bloki.
- Peamine järjepidevus võib olla hõivatud või, mis on tõenäolisem, ootab ise mingit operatsiooni lõpetamist, mis oleks pidanud algama taustajärjest (kuigi selles konkreetses näites seda ei ole, sünkroonsed saatmised peamisele järjepidevusele taustast on juba probleem).
sync-i puhul ei saa taustajärjest lõpetada enne, kui peamine järjepidevus ei täida saadetud bloki. Kui peamine järjepidevus on juba blokeeritud (näiteks ootab taustajärjesti tehtud operatsiooni lõpetamist, mis omakorda ootab peamist järjepidevust või on lihtsalt hõivatud), tekib tsükliline ootamine ehk deadlock.
Õige lahendus:
Kasutada asünkroonset saatmist peamisele järjepidevusele UI uuendamiseks.
// Õige lahendus: UI uuendamine asünkroonselt peamisele järjepidevusele
DispatchQueue.global().async {
// Teeme mingit taustatööd...
print("Taustatöö käib")
// Saadame UI uuendamise asünkroonselt peamisele järjepidevusele
DispatchQueue.main.async {
print("Uuendame UI-d peamise järjepidevuse kaudu")
// someLabel.text = "Uuendatud taustast" // Õige koht UI uuendamiseks
}
print("Taustatöö lõpetatud")
}
Siin taustajärjepidevus ei blokeeru, kui saadab bloki peamisele järjepidevusele, võimaldades nii taust- kui ka peamisel järjepidevusel töötada sõltumatult, vältides deadlocki.