setNeedsDisplay() — adalah metode instance UIView yang menandai tampilan sebagai perlu digambar ulang. Tidak seperti pemanggilan langsung draw(_:), setNeedsDisplay() hanya mengatur flag dirty untuk tampilan dan mengembalikan kendali segera. Sistem memproses permintaan ini dalam siklus render terdekat, memungkinkan penggabungan beberapa pemanggilan menjadi satu operasi penggambaran. Menurut Apple Documentation (2025), penggambaran ulang yang ditangguhkan melalui setNeedsDisplay() adalah satu-satunya cara yang benar untuk memperbarui konten UIView kustom.
Poin Utama
setNeedsDisplay() — adalah metode UIView yang memberi sinyal ke sistem bahwa konten tampilan sudah usang dan perlu render ulang. Metode ini tidak menerima parameter dan mengembalikan void. Setelah pemanggilan, tampilan ditandai sebagai dirty, dan dalam siklus penggambaran terdekat sistem memanggil draw(_:) untuk tampilan ini.
Fitur utamanya adalah asinkronitas. Beberapa pemanggilan setNeedsDisplay() secara berurutan untuk tampilan yang sama tidak akan menghasilkan beberapa pemanggilan draw(_:) — sistem menggabungkannya menjadi satu operasi. Ini sangat penting untuk kinerja: jika properti tampilan berubah beberapa kali per frame, draw(_:) hanya dipanggil satu kali.
Mekanisme penggambaran ulang yang ditangguhkan didasarkan pada siklus render UIKit. Ketika setNeedsDisplay() dipanggil, sistem mengatur flag internal layer.needsDisplay menjadi true. Di akhir run loop saat ini, sistem melewati semua layer dirty dan memanggil draw(_:) untuk masing-masing.
UIKit run loop mencakup fase update, di mana tampilan dirty diproses. Dalam fase ini, layoutSubviews() dipanggil jika diperlukan, kemudian draw(_:) untuk semua tampilan yang ditandai. Setelah penggambaran selesai, hasilnya dikirim ke GPU melalui Core Animation untuk komposisi.
class ProgressView: UIView {
var progress: CGFloat = 0 {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let ctx = UIGraphicsGetCurrentContext() else { return }
// Latar belakang
ctx.setFillColor(UIColor.lightGray.cgColor)
ctx.fill(rect)
// Bilah progres
let fillRect = CGRect(x: rect.minX, y: rect.minY,
width: rect.width * progress, height: rect.height)
ctx.setFillColor(UIColor.systemGreen.cgColor)
ctx.fill(fillRect)
}
}
Dalam contoh ini, progressView memperbarui progress, dan setiap setter secara otomatis memanggil setNeedsDisplay(). Sistem akan menunggu akhir run loop dan memanggil draw(_:) dengan nilai progress saat ini. Jika progress berubah tiga kali dalam satu frame, draw(_:) hanya akan dieksekusi satu kali — dengan nilai terakhir.
Metode setNeedsDisplay(_:) menerima parameter rect bertipe CGRect, yang membatasi area penggambaran ulang. Ini memungkinkan penggambaran ulang hanya bagian tampilan yang berubah, bukan keseluruhan. Perbedaan kinerja menjadi terlihat saat bekerja dengan tampilan besar di mana perubahan hanya mempengaruhi area kecil.
| Karakteristik | setNeedsDisplay() | setNeedsDisplay(_:) |
|---|---|---|
| Parameter | Tidak ada | CGRect — area penggambaran ulang |
| Area penggambaran ulang | Seluruh bounds tampilan | Hanya persegi panjang yang ditentukan |
| Kinerja | Lebih rendah pada tampilan besar | Lebih tinggi pada perubahan parsial |
| Parameter rect di draw(_:) | Seluruh bounds | Persegi panjang yang ditentukan |
| Kapan digunakan | Perubahan seluruh konten | Perubahan titik (kursor, highlight) |
Untuk grafis kompleks, disarankan untuk menggambar seluruh scene dalam konteks offscreen terlebih dahulu, kemudian memanggil setNeedsDisplay(_:) hanya untuk area yang berubah. Ini adalah teknik standar dalam aplikasi menggambar dan editor grafis di iOS.
displayIfNeeded() — adalah metode sinkron yang segera memulai penggambaran ulang semua tampilan dirty dalam hierarki, tanpa menunggu akhir run loop. Tidak seperti setNeedsDisplay() yang hanya mengatur flag, displayIfNeeded() memaksa eksekusi segera dari draw(_:).
Apple merekomendasikan penggunaan displayIfNeeded() hanya dalam kasus ekstrem, ketika hasil penggambaran diperlukan segera — misalnya, sebelum membuat screenshot atau saat pembuatan gambar sinkron untuk UIGraphicsImageRenderer. Dalam skenario biasa, model asinkron melalui setNeedsDisplay() lebih disukai karena tidak memblokir thread utama.
// Asinkron — direkomendasikan
someView.setNeedsDisplay()
// Sinkron — hanya bila diperlukan
someView.setNeedsDisplay()
someView.displayIfNeeded() // draw(_:) dipanggil segera
Pemanggilan displayIfNeeded() tanpa setNeedsDisplay() sebelumnya tidak akan memberikan efek — metode ini hanya memproses tampilan yang sudah ditandai sebagai dirty. Jika tidak ada tampilan yang memerlukan penggambaran ulang, displayIfNeeded() akan selesai tanpa memanggil draw(_:).
Pemanggilan setNeedsDisplay() yang sering dapat menurunkan kinerja, terutama selama animasi. Mari kita lihat strategi optimalisasi utama.
Alih-alih memanggil setNeedsDisplay() pada setiap perubahan properti individu, kumpulkan perubahan dan panggil metode satu kali setelah menerapkan semua pembaruan. Misalnya, saat mengubah warna, ukuran, dan posisi elemen — panggil setNeedsDisplay() satu kali setelah mengatur semua properti.
Jika properti dapat dianimasi melalui CALayer (backgroundColor, opacity, position, transform), gunakan Core Animation daripada draw(_:). Properti CALayer diperbarui di GPU tanpa memanggil draw(_:), memberikan 60 FPS tanpa membebani CPU.
Untuk mengelompokkan beberapa perubahan dalam satu lintasan render, gunakan CATransaction. Ini memungkinkan penggabungan beberapa setNeedsDisplay() menjadi satu operasi draw(_:) di akhir transaksi.
CATransaction.begin()
CATransaction.setDisableActions(true)
view1.setNeedsDisplay()
view2.setNeedsDisplay()
view3.setNeedsDisplay()
CATransaction.commit()
Jangan menyalahgunakan displayIfNeeded() — penggambaran ulang sinkron memblokir main thread dan dapat menyebabkan penurunan frame. Gunakan hanya untuk operasi di mana hasil penggambaran sangat penting sebelum akhir run loop saat ini.
Pertanyaan yang Sering Diajukan
Tidak, pemanggilan langsung draw(_:) dilarang. setNeedsDisplay() dengan benar menandai tampilan sebagai dirty, dan sistem memanggil draw(_:) pada momen yang tepat dalam siklus render. Pemanggilan langsung draw(_:) mengabaikan mekanisme caching dan dapat menyebabkan keadaan tidak konsisten.
Beberapa pemanggilan setNeedsDisplay() untuk tampilan yang sama digabungkan oleh sistem menjadi satu pemanggilan draw(_:). Ini terjadi karena metode ini hanya mengatur dirty flag, yang direset hanya setelah eksekusi nyata draw(_:) di akhir run loop.
setNeedsDisplay() meminta penggambaran ulang konten tampilan (pemanggilan draw(_:)). setNeedsLayout() meminta penataan ulang subview (pemanggilan layoutSubviews()). layoutSubviews() dapat menyebabkan perubahan ukuran, yang pada gilirannya dapat memicu penggambaran ulang.
setNeedsDisplay(_:) harus digunakan untuk perubahan titik: pergerakan kursor, perubahan warna area yang dipilih, pembaruan bagian grafik. Ini membatasi area penggambaran ulang dan meningkatkan kinerja dibandingkan dengan penggambaran ulang penuh seluruh tampilan.
Secara default, perubahan frame atau bounds tidak memanggil setNeedsDisplay(). Sistem hanya memindahkan tampilan. Jika penggambaran ulang diperlukan saat perubahan ukuran, atur properti contentMode ke nilai .redraw — maka UIKit akan secara otomatis memanggil setNeedsDisplay() setiap kali bounds berubah.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga