setNeedsDisplay() — bu UIView nümunə metodudur, görünüşü təkrar çəkilmə tələb edən kimi qeyd edir. Birbaşa draw(_:) çağırışından fərqli olaraq, setNeedsDisplay() yalnız görünüş üçün dirty bayrağı təyin edir və idarəni dərhal qaytarır. Sistem bu sorğunu ən yaxın render dövründə emal edir, bu da bir neçə çağırışı bir çəkmə əməliyyatında birləşdirməyə imkan verir. Apple Documentation (2025)-ə görə, setNeedsDisplay() vasitəsilə təxirə salınmış yenidən çəkmə fərdi UIView məzmununun yenilənməsinin yeganə düzgün üsuludur.
Əsas məqamlar
setNeedsDisplay() — bu UIView metodudur, sistemə görünüş məzmununun köhnəldiyini və təkrar render tələb etdiyini bildirir. Metod parametr qəbul etmir və void qaytarır. Çağırışdan sonra görünüş dirty kimi qeyd olunur və ən yaxın çəkmə dövründə sistem bu görünüş üçün draw(_:) çağırır.
Əsas xüsusiyyət asinxronluqdur. Eyni görünüş üçün ardıcıl bir neçə setNeedsDisplay() çağırışı çoxsaylı draw(_:) çağırışlarına səbəb olmur — sistem onları bir əməliyyatda birləşdirir. Bu performans üçün kritik əhəmiyyət daşıyır: görünüş xüsusiyyəti kadrda bir neçə dəfə dəyişərsə, draw(_:) yalnız bir dəfə çağırılır.
Təxirə salınmış yenidən çəkmə mexanizmi UIKit render dövrünə əsaslanır. setNeedsDisplay() çağırıldıqda, sistem daxili layer.needsDisplay bayrağını true olaraq təyin edir. Cari run loop sonunda sistem bütün dirty-qatları gəzərək hər biri üçün draw(_:) çağırır.
UIKit run loop dirty-görünüşlərin emal edildiyi update mərhələsini əhatə edir. Bu mərhələdə lazım olduqda layoutSubviews() çağırılır, sonra bütün qeyd olunmuş görünüşlər üçün draw(_:) yerinə yetirilir. Çəkmə tamamlandıqdan sonra nəticə kompozitinq üçün Core Animation vasitəsilə GPU-ya ötürülür.
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)
// Proqres 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)
}
}
Bu nümunədə progressView progress dəyərini yeniləyir və hər setter avtomatik olaraq setNeedsDisplay() çağırır. Sistem run loop sonunu gözləyəcək və draw(_:)-i cari progress dəyəri ilə çağıracaq. Əgər progress bir kadrda üç dəfə dəyişərsə, draw(_:) yalnız bir dəfə — son dəyərlə yerinə yetiriləcək.
setNeedsDisplay(_:) metodu yenidən çəkmə sahəsini məhdudlaşdıran rect parametri (CGRect tipi) qəbul edir. Bu, görünüşün yalnız dəyişmiş hissəsini yenidən çəkməyə imkan verir, bütünlüklə deyil. Performans fərqi dəyişikliklərin kiçik bir sahəyə toxunduğu böyük görünüşlərlə işləyərkən nəzərə çarpır.
| Xüsusiyyət | setNeedsDisplay() | setNeedsDisplay(_:) |
|---|---|---|
| Parametr | Yoxdur | CGRect — yenidən çəkmə sahəsi |
| Yenidən çəkmə sahəsi | Görünüşün bütün bounds | Yalnız göstərilən düzbucaq |
| Performans | Böyük görünüşlərdə aşağı | Qismən dəyişikliklərdə yüksək |
| draw(_:) parametr rect | Bütün bounds | Göstərilən düzbucaq |
| Nə vaxt istifadə etməli | Bütün məzmunun dəyişməsi | Nöqtəvi dəyişikliklər (kursor, highlight) |
Mürəkkəb qrafika üçün əvvəlcə bütün səhnəni offscreen kontekstində çəkmək, sonra isə yalnız dəyişmiş sahə üçün setNeedsDisplay(_:) çağırmaq tövsiyə olunur. Bu iOS-da çəkmə tətbiqləri və qrafik redaktorları üçün standart texnikadır.
displayIfNeeded() — bu sinxron metoddur, run loop sonunu gözləmədən iyerarxiyadakı bütün dirty-görünüşlərin yenidən çəkilməsini dərhal işə salır. Yalnız bayraq təyin edən setNeedsDisplay()-dən fərqli olaraq, displayIfNeeded() draw(_:)-in dərhal yerinə yetirilməsini məcbur edir.
Apple displayIfNeeded()-dən yalnız həddindən artıq zəruri hallarda istifadə etməyi tövsiyə edir — məsələn, ekran görüntüsü yaratmazdan əvvəl və ya UIGraphicsImageRenderer üçün sinxron şəkil generasiyası zamanı. Adi ssenarilərdə setNeedsDisplay() vasitəsilə asinxron model üstünlük təşkil edir, çünki əsas axını bloklamır.
// Asinxron — tövsiyə olunur
someView.setNeedsDisplay()
// Sinxron — yalnız zəruri olduqda
someView.setNeedsDisplay()
someView.displayIfNeeded() // draw(_:) dərhal çağırıldı
Əvvəlcədən setNeedsDisplay() çağırılmadan displayIfNeeded() çağırışı effekt verməyəcək — metod yalnız artıq dirty kimi qeyd olunmuş görünüşləri emal edir. Heç bir görünüş yenidən çəkmə tələb etmirsə, displayIfNeeded() draw(_:) çağırmadan tamamlanır.
Tez-tez setNeedsDisplay() çağırışları performansı aşağı sala bilər, xüsusən animasiya zamanı. Əsas optimallaşdırma strategiyalarını nəzərdən keçirək.
Ayrı-ayrı xüsusiyyətlərin hər dəyişməsində setNeedsDisplay() çağırmaq əvəzinə, dəyişiklikləri toplayın və bütün yeniləmələr tətbiq edildikdən sonra metodu bir dəfə çağırın. Məsələn, elementin rəngi, ölçüsü və mövqeyi dəyişdikdə — bütün xüsusiyyətlər təyin edildikdən sonra bir dəfə setNeedsDisplay() çağırın.
Xüsusiyyət CALayer vasitəsilə animasiya edilə bilərsə (backgroundColor, opacity, position, transform), draw(_:) əvəzinə Core Animation istifadə edin. CALayer xüsusiyyətləri draw(_:) çağırmadan GPU-da yenilənir, bu da CPU yükləmədən 60 FPS təmin edir.
Bir neçə dəyişikliyi bir render keçidində qruplaşdırmaq üçün CATransaction istifadə edin. Bu, bir neçə setNeedsDisplay()-i əməliyyat sonunda bir draw(_:) əməliyyatında birləşdirməyə imkan verir.
CATransaction.begin()
CATransaction.setDisableActions(true)
view1.setNeedsDisplay()
view2.setNeedsDisplay()
view3.setNeedsDisplay()
CATransaction.commit()
displayIfNeeded() istifadəsindən çəkinin — sinxron yenidən çəkmə main thread-i bloklayır və kadr düşməsinə səbəb ola bilər. Onu yalnız cari run loop tamamlanmazdan əvvəl çəkmə nəticəsinin kritik əhəmiyyət daşıdığı əməliyyatlar üçün istifadə edin.
Tez-tez verilən suallar
Xeyr, birbaşa draw(_:) çağırışı qadağandır. setNeedsDisplay() görünüşü düzgün şəkildə dirty kimi qeyd edir və sistem render dövrünün lazımi anında draw(_:) çağırır. Birbaşa draw(_:) çağırışı keşləmə mexanizmini nəzərə almır və uyğunsuz vəziyyətə səbəb ola bilər.
Eyni görünüş üçün bir neçə setNeedsDisplay() çağırışı sistem tərəfindən bir draw(_:) çağırışında birləşdirilir. Bu, metodun yalnız dirty flag təyin etməsi səbəbindən baş verir — bu bayraq yalnız run loop sonunda draw(_:) real icrasından sonra sıfırlanır.
setNeedsDisplay() görünüş məzmununun yenidən çəkilməsini tələb edir (draw(_:) çağırışı). setNeedsLayout() subview-ların yenidən yerləşdirilməsini tələb edir (layoutSubviews() çağırışı). layoutSubviews() ölçülərin dəyişməsinə səbəb ola bilər, bu da öz növbəsində yenidən çəkməyə səbəb ola bilər.
setNeedsDisplay(_:) nöqtəvi dəyişikliklərdə istifadə edilməlidir: kursor hərəkəti, seçilmiş sahənin rənginin dəyişməsi, qrafikin hissəsinin yenilənməsi. Bu, yenidən çəkmə sahəsini məhdudlaşdırır və bütün görünüşün tam yenidən çəkilməsi ilə müqayisədə performansı artırır.
Standart olaraq frame və ya bounds dəyişməsi setNeedsDisplay() çağırmır. Sistem sadəcə görünüşü hərəkət etdirir. Ölçü dəyişikliyində yenidən çəkmə tələb olunarsa, contentMode xüsusiyyətinə .redraw dəyərini təyin edin — onda UIKit bounds hər dəyişdikdə avtomatik olaraq setNeedsDisplay() çağıracaq.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun