draw(_:) dan drawRect — apa itu, pemanggilan dan override

Penulis: IT Sectr Diterbitkan: 2026-07-20 Waktu membaca: 7 mnt

draw(_:) / drawRect — adalah metode kelas UIView (di Swift) dan analognya di Objective-C (drawRect:), yang bertanggung jawab untuk merender konten view menggunakan Core Graphics. Sistem memanggil metode ini secara otomatis saat pertama kali view muncul di layar dan setelah pemanggilan setNeedsDisplay(). Menurut Apple Documentation (2025), draw(_:) adalah satu-satunya metode di mana pengembang memiliki akses ke konteks grafis layar saat ini untuk menggambar kustom. Melakukan override draw(_:) memberikan kendali penuh atas tampilan komponen — dari bentuk geometris sederhana hingga grafis animasi yang kompleks.

Poin Utama

  • draw(_:) — metode UIView untuk menggambar kustom melalui Core Graphics, tidak dipanggil langsung oleh pengembang
  • drawRect: — padanan draw(_:) di Objective-C, berbeda secara sintaks, identik secara fungsional
  • CGContext — konteks grafis yang tersedia di dalam draw(_:) untuk semua operasi menggambar
  • setNeedsDisplay() — satu-satunya cara yang benar untuk meminta pemanggilan ulang draw(_:) dari sisi pengembang
  • UIGraphicsGetCurrentContext() — fungsi untuk mendapatkan konteks saat ini di dalam draw(_:), langkah wajib sebelum menggambar

Apa itu draw(_:) / drawRect

draw(_:) — adalah metode instance UIView yang dipanggil UIKit untuk merender konten view. Di dalam metode ini, pengembang mendapatkan akses ke konteks grafis CGContext dan menggunakan API Core Graphics untuk menggambar garis, isian, teks, dan gambar. drawRect: di Objective-C melakukan fungsi yang sama, tetapi dengan sintaks yang berbeda: satu-satunya parameter adalah CGRect yang menentukan area yang akan digambar ulang.

Menurut Apple Engineering (2024), draw(_:) bekerja melalui CPU-rendering Bitmap Graphics Context, yang memberikan fleksibilitas maksimal, tetapi membutuhkan lebih banyak sumber daya dibandingkan CALayer. Keputusan untuk menggunakan draw(_:) diambil berdasarkan kompleksitas grafis dan persyaratan kinerja.

Signature metode di Swift dan Objective-C

Di Swift, metode dideklarasikan sebagai override func draw(_ rect: CGRect), di mana rect adalah persegi panjang yang perlu digambar ulang. Di Objective-C signature-nya adalah - (void)drawRect:(CGRect)rect. Parameter rect bisa lebih kecil dari bounds view saat penggambaran ulang parsial melalui setNeedsDisplay(_:).

objective-c
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
    CGContextFillRect(context, rect);
}

Kapan sistem memanggil draw(_:)

Sistem secara otomatis memanggil draw(_:) dalam skenario yang ditentukan secara ketat. Memahami pemicu ini membantu menghindari penggambaran ulang yang tidak perlu dan mengoptimalkan kinerja view. Di bawah ini tercantum semua kasus pemanggilan otomatis metode.

  • Render pertama — ketika view pertama kali ditambahkan ke hierarki dan menjadi terlihat di layar
  • setNeedsDisplay() — setelah pemanggilan metode ini oleh sistem pada siklus penggambaran terdekat
  • setNeedsDisplay(_:) — sama, tetapi dengan menentukan persegi panjang spesifik untuk digambar ulang
  • contentMode — saat bounds berubah, jika contentMode memerlukan penggambaran ulang (misalnya .redraw)
  • setNeedsLayout() — dalam beberapa kasus setelah penataan ulang subview mungkin diperlukan penggambaran ulang

Dokumentasi Apple memperingatkan: jangan pernah memanggil draw(_:) secara langsung. Sistem sendiri yang memutuskan kapan akan melakukan penggambaran, dan pemanggilan langsung merusak mekanisme caching internal. Untuk meminta penggambaran ulang, selalu gunakan setNeedsDisplay() atau setNeedsDisplay(_:).

Cara melakukan override draw(_:) di Swift

Melakukan override draw(_:) di Swift dimulai dengan mendapatkan konteks grafis dan pemanggilan Core Graphics selanjutnya. Disarankan untuk membuat metode terpisah untuk blok logika penggambaran — ini meningkatkan keterbacaan dan kemudahan pengujian kode.

swift
override func draw(_ rect: CGRect) {
    super.draw(rect)

    guard let context = UIGraphicsGetCurrentContext() else { return }

    // Parameter garis
    context.setStrokeColor(UIColor.darkGray.cgColor)
    context.setLineWidth(2.0)

    // Menggambar segitiga
    context.move(to: CGPoint(x: rect.midX, y: rect.minY + 10))
    context.addLine(to: CGPoint(x: rect.maxX - 10, y: rect.maxY - 10))
    context.addLine(to: CGPoint(x: rect.minX + 10, y: rect.maxY - 10))
    context.closePath()
    context.strokePath()
}

Dalam contoh ini draw(_:) menggambar segitiga dengan garis tepi abu-abu gelap setebal 2 piksel. Pemanggilan super.draw(rect) di awal metode direkomendasikan oleh Apple untuk mempertahankan logika penggambaran induk, meskipun implementasi default draw(_:) di UIView kosong.

Aturan idempotensi draw(_:)

Setiap pemanggilan draw(_:) harus memberikan hasil yang identik dengan data masukan yang sama. Ini memungkinkan sistem menyimpan cache hasil dan tidak memanggil draw(_:) lagi jika konten view tidak berubah. Jangan gunakan nilai acak, waktu sistem, atau permintaan jaringan di dalam draw(_:).

drawRect: di Objective-C dan perbedaan dengan draw(_:)

drawRect: — secara historis merupakan versi pertama metode, muncul di iOS 2.0 bersama Objective-C. Di Swift metode ini diubah namanya menjadi draw(_:) dengan menggunakan parameter eksternal _. Secara fungsional metode ini identik: keduanya menerima CGRect dari area yang akan digambar ulang dan menggunakan UIGraphicsGetCurrentContext() untuk mengakses konteks grafis.

Karakteristikdraw(_:) (Swift)drawRect: (Objective-C)
Signatureoverride func draw(_ rect: CGRect)- (void)drawRect:(CGRect)rect
Pemanggilan supersuper.draw(rect)[super drawRect:rect]
KonteksUIGraphicsGetCurrentContext()UIGraphicsGetCurrentContext()
Parameter rectrect: CGRectCGRect rect
KinerjaIdentikIdentik

Saat migrasi proyek dari Objective-C ke Swift, mengganti nama metode adalah salah satu tugas pertama. Xcode menyediakan konverter otomatis, tetapi drawRect: memerlukan pembaruan manual ke draw(_:). Menurut Apple (2024), versi Swift draw(_:) lebih disukai untuk proyek baru.

Optimasi menggambar di draw(_:)

draw(_:) dijalankan di CPU, dan implementasi yang tidak optimal dapat menyebabkan penurunan frame dan kinerja rendah. Apple merekomendasikan beberapa pendekatan yang terbukti untuk mempercepat penggambaran.

Minimalkan jumlah operasi menggambar

Setiap operasi Core Graphics (move(to:), addLine(to:), strokePath) memiliki biaya tambahan. Kelompokkan operasi dan gunakan CGPath untuk bentuk kompleks — jalur dibuat sekali dan digunakan kembali di setiap pemanggilan draw(_:).

Gunakan UIBezierPath untuk objek vektor

UIBezierPath — adalah pembungkus Objective-C di sekitar CGPath yang menyediakan API sederhana untuk membuat bentuk. Buat UIBezierPath sebelumnya (misalnya di inisialisator) dan cukup panggil fill() atau stroke() di dalam draw(_:).

swift
private let starPath: UIBezierPath = {
    let path = UIBezierPath()
    // Membangun bentuk bintang
    path.move(to: CGPoint(x: 50, y: 0))
    for i in 1...5 {
        let angle = CGFloat(i) * 4 * CGFloat.pi / 5
        path.addLine(to: CGPoint(x: 50 + 40 * cos(angle),
                               y: 50 + 40 * sin(angle)))
    }
    path.close()
    return path
}()

override func draw(_ rect: CGRect) {
    UIColor.systemYellow.setFill()
    starPath.fill()
}

Kesalahan umum saat bekerja dengan draw(_:)

Pengembang sering melakukan kesalahan yang sama saat melakukan override draw(_:). Pengetahuan tentang pola-pola ini membantu menghindari bug dan penurunan kinerja. Mari kita lihat masalah yang paling umum dan solusinya.

  • Pemanggilan langsung draw(_:) — jangan pernah memanggil draw(_:) secara langsung. Gunakan setNeedsDisplay() untuk meminta penggambaran ulang. Pemanggilan langsung merusak caching dan dapat menyebabkan tampilan yang salah.
  • Komputasi berat di dalam draw(_:) — draw(_:) harus seringan mungkin. Buat UIBezierPath, gambar, dan objek berat lainnya di luar metode, inisialisasi sekali.
  • Membuat objek di dalam draw(_:) — konstruksi UIColor, UIFont, dan UIGraphicsImageRenderer di dalam draw(_:) menciptakan beban memori tambahan. Pindahkan pembuatan objek ke properti kelas.
  • Mengabaikan parameter rect — rect menunjukkan area yang memerlukan penggambaran ulang. Menggambar di luar rect ditolak oleh sistem, tetapi menghabiskan sumber daya. Periksa intersection dengan rect sebelum menggambar.
  • Tidak ada super.draw(rect) — meskipun implementasi UIView kosong, Apple merekomendasikan pemanggilan super.draw(rect) untuk kompatibilitas dengan perubahan UIKit di masa depan.

Dengan mengikuti aturan ini, Anda akan memastikan penggambaran view kustom yang stabil dan cepat di proyek iOS mana pun. Profil-lah draw(_:) melalui Instruments (Core Animation) untuk melihat waktu eksekusi nyata dan titik lemah.

Pertanyaan yang Sering Diajukan

Bisakah draw(_:) dipanggil secara langsung?

Tidak, pemanggilan langsung draw(_:) dilarang oleh dokumentasi Apple. Sistem sendiri yang mengelola siklus penggambaran. Untuk meminta penggambaran ulang, gunakan setNeedsDisplay(), yang dengan benar menandai view sebagai memerlukan pembaruan pada siklus rendering terdekat.

Apa perbedaan drawRect: dengan draw(_:)?

Secara fungsional metode ini identik. drawRect: digunakan di Objective-C, draw(_:) di Swift. Keduanya menerima CGRect dari area penggambaran ulang dan menggunakan konteks Core Graphics yang sama melalui UIGraphicsGetCurrentContext().

Mengapa draw(_:) tidak dipanggil untuk UIView kosong?

Apple mengoptimalkan rendering: jika UIView tidak memiliki override draw(_:), sistem tidak membuat konteks bitmap untuknya. Ini menghemat memori. Jika override ada tetapi metode tidak dipanggil — periksa apakah frame view tidak nol dan view terlihat.

Seberapa sering sistem memanggil draw(_:)?

Hanya saat diperlukan: rendering pertama, setelah setNeedsDisplay(), saat bounds berubah dengan contentMode = .redraw. Dalam keadaan statis, draw(_:) tidak dipanggil lagi, yang menghemat sumber daya CPU dan baterai.

Apakah perlu memanggil super.draw(rect) di Swift?

Apple merekomendasikan pemanggilan super.draw(rect) di awal metode yang di-override. Meskipun implementasi UIView saat ini kosong, pemanggilan super memastikan kompatibilitas dengan versi UIKit mendatang dan merupakan praktik yang baik.

Ringkasan

  • draw(_:) / drawRect — metode penggambaran utama UIView di Swift dan Objective-C, dipanggil secara otomatis oleh sistem
  • CGContext — konteks grafis Core Graphics yang tersedia di dalam draw(_:) melalui UIGraphicsGetCurrentContext()
  • setNeedsDisplay() — cara yang benar untuk meminta penggambaran ulang; pemanggilan langsung draw(_:) dilarang
  • Idempotensi — draw(_:) harus memberikan hasil yang sama dengan masukan yang sama untuk caching yang benar
  • UIBezierPath — buat jalur di luar draw(_:) untuk meminimalkan beban CPU pada setiap pemanggilan
  • Parameter rect — berisi area penggambaran ulang; gunakan intersection untuk optimasi — jangan menggambar di luar batasnya
  • Profil — periksa kinerja draw(_:) melalui Instruments Core Animation untuk mendeteksi operasi lambat

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.

Diskusikan proyek

Baca juga