setNeedsDisplay(): metodun mahiyyəti və iOS-da yenidən çəkmə mexanizmi

Müəllif: IT Sectr Dərc olunub: 2026-07-20 Oxuma vaxtı: 6 dəq

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() — UIView-in təxirə salınmış yenidən çəkmə sorğusu, draw(_:) sinxron çağırmır
  • dirty flag — setNeedsDisplay() tərəfindən təyin edilən və draw(_:) sonrası sıfırlanan daxili görünüş bayrağı
  • setNeedsDisplay(_:) — yalnız göstərilən sahənin qismən yenidən çəkilməsi üçün CGRect ilə yükləmə
  • displayIfNeeded() — məcburi sinxron yenidən çəkmə, ani yeniləmə üçün istifadə olunur
  • Render dövrü — sistem dirty görünüşləri run loop sonunda emal edir, bir neçə sorğunu bir keçiddə birləşdirir

setNeedsDisplay() nədir

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ə necə işləyir

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.

Run loop və render addımları

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.

swift
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() vs setNeedsDisplay(_:)

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ətsetNeedsDisplay()setNeedsDisplay(_:)
ParametrYoxdurCGRect — yenidən çəkmə sahəsi
Yenidən çəkmə sahəsiGörünüşün bütün boundsYalnız göstərilən düzbucaq
PerformansBöyük görünüşlərdə aşağıQismən dəyişikliklərdə yüksək
draw(_:) parametr rectBütün boundsGöstərilən düzbucaq
Nə vaxt istifadə etməliBütün məzmunun dəyişməsiNö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() və setNeedsDisplay()

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.

swift
    // 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.

setNeedsDisplay() çağırışlarının optimallaşdırılması

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.

Model vasitəsilə dəyişikliklərin birləşdirilməsi

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.

Animasiya olunan xüsusiyyətlər üçün CALayer istifadəsi

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.

CATransaction vasitəsilə toplu yeniləmə

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.

swift
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

setNeedsDisplay() əvəzinə birbaşa draw(_:) çağırmaq olarmı?

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.

Çoxsaylı setNeedsDisplay() çağırışlarında nə baş verir?

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() setNeedsLayout()-dan nə ilə fərqlənir?

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ə vaxt istifadə edilməlidir?

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.

Frame dəyişməsi avtomatik setNeedsDisplay() çağırırmı?

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ə

  • setNeedsDisplay() — dirty flag təyin etməklə təxirə salınmış yenidən çəkmə tələbi üçün UIView-in asinxron metodu
  • setNeedsDisplay(_:) — yalnız göstərilən sahənin qismən yenidən çəkilməsi üçün CGRect ilə yükləmə, performansı optimallaşdırır
  • displayIfNeeded() — dirty-görünüşlərin dərhal yenidən çəkilməsi üçün sinxron metod, yalnız həddindən artıq zərurət olduqda istifadə olunur
  • Run loop — sistem dirty-görünüşləri cari dövrün sonunda emal edir, çoxsaylı çağırışları bir draw(_:) keçidində birləşdirir
  • CALayer — animasiya olunan xüsusiyyətlər (position, opacity) üçün draw(_:) əvəzinə Core Animation istifadə edin — bu daha səmərəlidir
  • CATransaction — bir neçə dəyişikliyi bir render dövründə qruplaşdırır, draw(_:) çağırışlarının sayını azaldır
  • contentMode = .redraw — görünüşün bounds dəyişdikdə avtomatik setNeedsDisplay() çağırışını aktivləşdirir

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.

Layihəni müzakirə et

Həm də oxuyun