setNeedsDisplay() — bu UIView namuna metodi bo‘lib, ko‘rinishni qayta chizish talab qiladigan deb belgilaydi. To‘g‘ridan-to‘g‘ri draw(_:) chaqiruvidan farqli o‘laroq, setNeedsDisplay() faqat ko‘rinish uchun dirty bayrog‘ini o‘rnatadi va boshqaruvni darhol qaytaradi. Tizim bu so‘rovni eng yaqin render siklida qayta ishlaydi, bu bir nechta chaqiruvlarni bitta chizish operatsiyasida birlashtirishga imkon beradi. Apple Documentation (2025) ga ko‘ra, setNeedsDisplay() orqali kechiktirilgan qayta chizish moslashtirilgan UIView tarkibini yangilashning yagona to‘g‘ri usulidir.
Asosiy fikrlar
setNeedsDisplay() — bu UIView metodi bo‘lib, tizimga ko‘rinish tarkibi eskirganligi va qayta render talab qilishini bildiradi. Metod parametr qabul qilmaydi va void qaytaradi. Chaqiruvdan so‘ng ko‘rinish dirty deb belgilanadi va eng yaqin chizish siklida tizim ushbu ko‘rinish uchun draw(_:) ni chaqiradi.
Asosiy xususiyat asinxronlik dir. Bir ko‘rinish uchun ketma-ket bir nechta setNeedsDisplay() chaqiruvi bir nechta draw(_:) chaqiruviga olib kelmaydi — tizim ularni bitta operatsiyada birlashtiradi. Bu ishlash uchun juda muhim: agar ko‘rinish xususiyati kadrda bir necha marta o‘zgarsa, draw(_:) faqat bir marta chaqiriladi.
Kechiktirilgan qayta chizish mexanizmi UIKit render sikliga asoslangan. setNeedsDisplay() chaqirilganda, tizim ichki layer.needsDisplay bayrog‘ini true ga o‘rnatadi. Joriy run loop oxirida tizim barcha dirty qatlamlardan o‘tib, har biri uchun draw(_:) ni chaqiradi.
UIKit run loop dirty ko‘rinishlar qayta ishlanadigan update bosqichini o‘z ichiga oladi. Ushbu bosqichda kerak bo‘lsa layoutSubviews() chaqiriladi, so‘ng barcha belgilangan ko‘rinishlar uchun draw(_:) bajariladi. Chizish tugagandan so‘ng natija kompoziting uchun Core Animation orqali GPU ga uzatiladi.
class ProgressView: UIView {
var progress: CGFloat = 0 {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let ctx = UIGraphicsGetCurrentContext() else { return }
// Fon
ctx.setFillColor(UIColor.lightGray.cgColor)
ctx.fill(rect)
// Progress bar
let fillRect = CGRect(x: rect.minX, y: rect.minY,
width: rect.width * progress, height: rect.height)
ctx.setFillColor(UIColor.systemGreen.cgColor)
ctx.fill(fillRect)
}
}
Ushbu misolda progressView progress ni yangilaydi va har bir setter avtomatik ravishda setNeedsDisplay() ni chaqiradi. Tizim run loop oxirini kutadi va draw(_:) ni joriy progress qiymati bilan chaqiradi. Agar progress bir kadrda uch marta o‘zgarsa, draw(_:) faqat bir marta — oxirgi qiymat bilan bajariladi.
setNeedsDisplay(_:) metodi qayta chizish hududini cheklovchi rect parametrini (CGRect turi) qabul qiladi. Bu ko‘rinishning faqat o‘zgargan qismini qayta chizishga imkon beradi, butunini emas. Ishlash farqi o‘zgarishlar kichik hududga ta‘sir qiladigan katta ko‘rinishlar bilan ishlaganda sezilarli bo‘ladi.
| Xususiyat | setNeedsDisplay() | setNeedsDisplay(_:) |
|---|---|---|
| Parametr | Yo‘q | CGRect — qayta chizish hududi |
| Qayta chizish hududi | Ko‘rinishning butun bounds | Faqat belgilangan to‘rtburchak |
| Ishlash | Katta ko‘rinishlarda past | Qisman o‘zgarishlarda yuqori |
| draw(_:) dagi rect parametri | Butun bounds | Belgilangan to‘rtburchak |
| Qachon ishlatish | Butun tarkibning o‘zgarishi | Nuqtaviy o‘zgarishlar (kursor, highlight) |
Murakkab grafikalar uchun avval butun sahnani offscreen kontekstida chizish, so‘ng faqat o‘zgargan hudud uchun setNeedsDisplay(_:) ni chaqirish tavsiya etiladi. Bu iOS-da chizish ilovalari va grafik muharrirlarida standart texnikadir.
displayIfNeeded() — bu sinxron metod bo‘lib, run loop oxirini kutmasdan ierarxiyadagi barcha dirty ko‘rinishlarning qayta chizilishini darhol boshlaydi. Faqat bayroq o‘rnatadigan setNeedsDisplay() dan farqli o‘laroq, displayIfNeeded() draw(_:) ning darhol bajarilishini majburlaydi.
Apple displayIfNeeded() dan faqat o‘ta zarur hollarda foydalanishni tavsiya qiladi — masalan, skrinshot yaratishdan oldin yoki UIGraphicsImageRenderer uchun sinxron tasvir generatsiyasida. Oddiy stsenariylarda setNeedsDisplay() orqali asinxron model afzalroq, chunki u asosiy oqimni bloklamaydi.
// Asinxron — tavsiya etiladi
someView.setNeedsDisplay()
// Sinxron — faqat kerak bo‘lganda
someView.setNeedsDisplay()
someView.displayIfNeeded() // draw(_:) darhol chaqirildi
Avval setNeedsDisplay() chaqirilmasdan displayIfNeeded() chaqiruvi samara bermaydi — metod faqat allaqachon dirty deb belgilangan ko‘rinishlarni qayta ishlaydi. Agar hech qanday ko‘rinish qayta chizishni talab qilmasa, displayIfNeeded() draw(_:) chaqirmasdan tugaydi.
Tez-tez setNeedsDisplay() chaqiruvlari ishlashni pasaytirishi mumkin, ayniqsa animatsiya paytida. Asosiy optimallashtirish strategiyalarini ko‘rib chiqamiz.
Alohida xususiyatlarning har bir o‘zgarishida setNeedsDisplay() chaqirish o‘rniga, o‘zgarishlarni to‘plang va barcha yangilanishlar qo‘llanilgandan so‘ng metodni bir marta chaqiring. Masalan, elementning rangi, o‘lchami va joylashuvi o‘zgarganda — barcha xususiyatlar o‘rnatilgandan so‘ng bir marta setNeedsDisplay() chaqiring.
Agar xususiyat CALayer orqali animatsiya qilinishi mumkin bo‘lsa (backgroundColor, opacity, position, transform), draw(_:) o‘rniga Core Animation dan foydalaning. CALayer xususiyatlari draw(_:) chaqirmasdan GPU da yangilanadi, bu CPU ni yuklamasdan 60 FPS ni ta‘minlaydi.
Bir nechta o‘zgarishlarni bir render o‘tishida guruhlash uchun CATransaction dan foydalaning. Bu bir nechta setNeedsDisplay() ni tranzaksiya oxirida bitta draw(_:) operatsiyasida birlashtirishga imkon beradi.
CATransaction.begin()
CATransaction.setDisableActions(true)
view1.setNeedsDisplay()
view2.setNeedsDisplay()
view3.setNeedsDisplay()
CATransaction.commit()
displayIfNeeded() dan suiiste‘mol qilmang — sinxron qayta chizish main thread ni bloklaydi va kadr tushishiga sabab bo‘lishi mumkin. Uni faqat joriy run loop tugashidan oldin chizish natijasi muhim bo‘lgan operatsiyalar uchun ishlating.
Ko‘p beriladigan savollar
Yo‘q, to‘g‘ridan-to‘g‘ri draw(_:) chaqiruvi ta‘qiqlangan. setNeedsDisplay() ko‘rinishni to‘g‘ri dirty deb belgilaydi va tizim render siklining kerakli momentida draw(_:) ni chaqiradi. To‘g‘ridan-to‘g‘ri draw(_:) chaqiruvi keshlash mexanizmini e‘tiborsiz qoldiradi va nomuvofiq holatga olib kelishi mumkin.
Bir ko‘rinish uchun bir nechta setNeedsDisplay() chaqiruvi tizim tomonidan bitta draw(_:) chaqiruvida birlashtiriladi. Bu metod faqat dirty flag ni o‘rnatgani uchun sodir bo‘ladi — bu bayroq faqat run loop oxirida draw(_:) haqiqiy bajarilishidan so‘ng tiklanadi.
setNeedsDisplay() ko‘rinish tarkibining qayta chizilishini so‘raydi (draw(_:) chaqiruvi). setNeedsLayout() subview-larning qayta joylashtirilishini so‘raydi (layoutSubviews() chaqiruvi). layoutSubviews() o‘lchamlarning o‘zgarishiga olib kelishi mumkin, bu esa o‘z navbatida qayta chizishni keltirib chiqarishi mumkin.
setNeedsDisplay(_:) nuqtaviy o‘zgarishlarda ishlatilishi kerak: kursor harakati, tanlangan hudud rangining o‘zgarishi, grafik qismining yangilanishi. Bu qayta chizish hududini cheklaydi va butun ko‘rinishning to‘liq qayta chizilishi bilan solishtirganda ishlashni oshiradi.
Standart bo‘yicha frame yoki bounds o‘zgarishi setNeedsDisplay() chaqirmaydi. Tizim shunchaki ko‘rinishni harakatlantiradi. Agar o‘lcham o‘zgarishida qayta chizish talab qilinsa, contentMode xususiyatiga .redraw qiymatini o‘rnating — u holda UIKit bounds har o‘zgarganda avtomatik ravishda setNeedsDisplay() ni chaqiradi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.