draw(_:) ve drawRect — nedir, çağrı ve geçersiz kılma

Yazar: IT Sectr Yayınlanma: 2026-07-20 Okuma süresi: 7 dk

draw(_:) / drawRect, UIView sınıfının (Swift'te) ve Objective-C'deki karşılığının (drawRect:) bir yöntemidir ve Core Graphics kullanarak görünüm içeriğinin render edilmesinden sorumludur. Sistem, görünüm ekranda ilk kez göründüğünde ve setNeedsDisplay() çağrısından sonra bu yöntemi otomatik olarak çağırır. Apple Belgeleri'ne (2025) göre draw(_:), geliştiricinin özel çizim için geçerli ekranın grafik bağlamına erişebildiği tek yöntemdir. draw(_:)'ı geçersiz kılmak, bileşenin görünümü üzerinde tam kontrol sağlar — basit geometrik şekillerden karmaşık animasyonlu grafiklere kadar.

Önemli Noktalar

  • draw(_:) — Core Graphics aracılığıyla özel çizim için UIView yöntemi, geliştirici tarafından doğrudan çağrılmaz
  • drawRect: — Objective-C'de draw(_:)'ın eşdeğeri, sözdizimsel olarak farklı, işlevsel olarak aynı
  • CGContext — tüm çizim işlemleri için draw(_:) içinde kullanılabilen grafik bağlamı
  • setNeedsDisplay() — geliştirici tarafından draw(_:)'ın yeniden çizilmesini istemenin tek doğru yolu
  • UIGraphicsGetCurrentContext() — draw(_:) içinde geçerli bağlamı alan işlev, çizimden önce zorunlu adım

draw(_:) / drawRect nedir

draw(_:), UIKit'in görünüm içeriğini render etmek için çağırdığı bir UIView örnek yöntemidir. Bu yöntemin içinde, geliştirici CGContext grafik bağlamına erişir ve çizgiler, dolgular, metin ve görüntüler çizmek için Core Graphics API'sini kullanır. Objective-C'de drawRect: aynı işlevi ancak farklı sözdizimiyle yerine getirir: tek parametre, yeniden çizilecek alanı belirten bir CGRect'tir.

Apple Engineering'e (2024) göre draw(_:), CPU tabanlı Bitmap Graphics Context renderi aracılığıyla çalışır ve maksimum esneklik sağlar ancak CALayer'a kıyasla daha fazla kaynak gerektirir. draw(_:) kullanma kararı, grafiğin karmaşıklığına ve performans gereksinimlerine göre verilir.

Swift ve Objective-C'de yöntem imzası

Swift'te yöntem override func draw(_ rect: CGRect) olarak bildirilir, burada rect yeniden çizilmesi gereken dikdörtgendir. Objective-C'de imza - (void)drawRect:(CGRect)rect şeklindedir. setNeedsDisplay(_:) aracılığıyla kısmi yeniden çizim sırasında rect parametresi görünümün bounds'undan daha küçük olabilir.

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

Sistem draw(_:)'ı ne zaman çağırır

Sistem, kesin olarak tanımlanmış senaryolarda otomatik olarak draw(_:)'ı çağırır. Bu tetikleyicileri anlamak, gereksiz yeniden çizimleri önlemeye ve görünüm performansını optimize etmeye yardımcı olur. Aşağıda yöntemin otomatik çağrılmasının tüm durumları listelenmiştir.

  • İlk render — görünüm ilk kez hiyerarşiye eklendiğinde ve ekranda görünür hale geldiğinde
  • setNeedsDisplay() — bu yöntem çağrıldıktan sonra sistem bir sonraki çizim döngüsünde yeniden çizer
  • setNeedsDisplay(_:) — yukarıdakiyle aynı, ancak yeniden çizim için belirli bir dikdörtgen belirtir
  • contentMode — bounds değiştiğinde, contentMode yeniden çizim gerektiriyorsa (örneğin .redraw)
  • setNeedsLayout() — bazı durumlarda, alt görünümlerin yeniden düzenlenmesinden sonra yeniden çizim gerekebilir

Apple belgeleri uyarır: draw(_:)'ı asla doğrudan çağırmayın. Sistem çizimi ne zaman yapacağına kendisi karar verir ve doğrudan çağrı dahili önbellekleme mekanizmasını bozar. Yeniden çizim istemek için her zaman setNeedsDisplay() veya setNeedsDisplay(_:) kullanın.

Swift'te draw(_:) nasıl geçersiz kılınır

Swift'te draw(_:)'ı geçersiz kılmak, grafik bağlamını almak ve ardından Core Graphics çağrılarıyla başlar. Çizimin mantıksal blokları için ayrı yöntemler oluşturulması önerilir — bu, kod okunabilirliğini ve test edilebilirliğini artırır.

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

    guard let context = UIGraphicsGetCurrentContext() else { return }

    // Line parameters
    context.setStrokeColor(UIColor.darkGray.cgColor)
    context.setLineWidth(2.0)

    // Drawing a triangle
    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()
}

Bu örnekte draw(_:), 2 piksel kalınlığında koyu gri bir çerçeveye sahip bir üçgen çizer. Yöntemin başında super.draw(rect) çağrısı, üst çizim mantığını korumak için Apple tarafından önerilir, ancak UIView'in varsayılan draw(_:) uygulaması boştur.

draw(_:)'ın idempotentlik kuralı

draw(_:)'ın her çağrısı, aynı girdi verileriyle aynı sonucu üretmelidir. Bu, sistemin sonucu önbelleğe almasına ve görünüm içeriği değişmediyse draw(_:)'ı tekrar çağırmamasına olanak tanır. draw(_:) içinde rastgele değerler, sistem saati veya ağ istekleri kullanmayın.

Objective-C'de drawRect: ve draw(_:)'dan farkları

drawRect: tarihsel olarak iOS 2.0'da Objective-C ile ortaya çıkan yöntemin ilk sürümüdür. Swift'te yöntem, dış parametre _ kullanılarak draw(_:) olarak yeniden adlandırılmıştır. İşlevsel olarak yöntemler aynıdır: her ikisi de yeniden çizilecek alanın CGRect'ini alır ve grafik bağlamına erişmek için UIGraphicsGetCurrentContext() kullanır.

Özellikdraw(_:) (Swift)drawRect: (Objective-C)
İmzaoverride func draw(_ rect: CGRect)- (void)drawRect:(CGRect)rect
super çağrısısuper.draw(rect)[super drawRect:rect]
BağlamUIGraphicsGetCurrentContext()UIGraphicsGetCurrentContext()
rect parametresirect: CGRectCGRect rect
PerformansAynıAynı

Bir projeyi Objective-C'den Swift'e taşırken yöntemi yeniden adlandırmak ilk görevlerden biridir. Xcode otomatik bir dönüştürücü sağlar, ancak drawRect: manuel olarak draw(_:)'a güncellenmelidir. Apple'a (2024) göre Swift sürümü draw(_:) yeni projeler için tercih edilir.

draw(_:) içinde çizim optimizasyonu

draw(_:) CPU'da çalışır ve optimal olmayan bir uygulama, kare düşüşlerine ve düşük performansa neden olabilir. Apple, çizimi hızlandırmak için birkaç kanıtlanmış yaklaşım önerir.

Çizim işlemlerinin sayısını en aza indirin

Her Core Graphics işleminin (move(to:), addLine(to:), strokePath) ek yükü vardır. İşlemleri gruplandırın ve karmaşık şekiller için CGPath kullanın — yol bir kez oluşturulur ve her draw(_:) çağrısında yeniden kullanılır.

Vektör nesneleri için UIBezierPath kullanın

UIBezierPath, şekiller oluşturmak için basit bir API sağlayan CGPath üzerinde bir Objective-C sarmalayıcısıdır. UIBezierPath'i önceden oluşturun (örneğin başlatıcıda) ve draw(_:) içinde yalnızca fill() veya stroke() çağırın.

swift
private let starPath: UIBezierPath = {
    let path = UIBezierPath()
    // Building a star shape
    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()
}

draw(_:) ile çalışırken yaygın hatalar

Geliştiriciler draw(_:)'ı geçersiz kılarken sıklıkla aynı hataları yaparlar. Bu kalıpları bilmek, hatalardan ve performans düşüşünden kaçınmaya yardımcı olur. En yaygın sorunlara ve çözümlerine bakalım.

  • draw(_:)'ı doğrudan çağırmak — draw(_:)'ı asla doğrudan çağırmayın. Yeniden çizim istemek için setNeedsDisplay() kullanın. Doğrudan çağrı önbelleği bozar ve yanlış görüntülemeye yol açabilir.
  • draw(_:) içinde ağır hesaplamalar — draw(_:) mümkün olduğunca hafif olmalıdır. UIBezierPath, resimler ve diğer ağır nesneleri yöntemin dışında oluşturun, bir kez başlatın.
  • draw(_:) içinde nesne oluşturma — draw(_:) içinde UIColor, UIFont ve UIGraphicsImageRenderer yapıları gereksiz bellek yükü oluşturur. Nesne oluşturmayı sınıf özelliklerine taşıyın.
  • rect parametresini yok saymak — rect, yeniden çizilmesi gereken alanı belirtir. rect dışında çizim sistem tarafından atılır ancak kaynak tüketir. Çizimden önce rect ile kesişimi kontrol edin.
  • super.draw(rect) eksikliği — UIView uygulaması boş olsa da Apple, gelecekteki UIKit değişiklikleriyle uyumluluk için super.draw(rect) çağrısını önerir.

Bu kuralları izleyerek, herhangi bir iOS projesinde kararlı ve hızlı özel görünüm çizimi sağlarsınız. Gerçek yürütme süresini ve darboğazları görmek için Instruments (Core Animation) aracılığıyla draw(_:)'ı profilleyin.

Sıkça Sorulan Sorular

draw(_:) doğrudan çağrılabilir mi?

Hayır, draw(_:)'ın doğrudan çağrılması Apple belgeleri tarafından yasaklanmıştır. Sistem çizim döngüsünü kendisi yönetir. Yeniden çizim istemek için setNeedsDisplay() kullanın; bu, görünümü en yakın render döngüsünde güncellenmesi gereken olarak doğru şekilde işaretler.

drawRect: draw(_:)'dan nasıl farklıdır?

İşlevsel olarak bu yöntemler aynıdır. drawRect: Objective-C'de kullanılır, draw(_:) Swift'te. Her ikisi de yeniden çizilecek alanın CGRect'ini alır ve UIGraphicsGetCurrentContext() aracılığıyla aynı Core Graphics bağlamını kullanır.

Boş bir UIView için draw(_:) neden çağrılmaz?

Apple render'ı optimize eder: Bir UIView'de geçersiz kılınmış draw(_:) yoksa, sistem onun için bitmap bağlamı oluşturmaz. Bu bellek tasarrufu sağlar. Geçersiz kılma varsa ancak yöntem çağrılmıyorsa — görünümün çerçevesinin sıfır olmadığını ve görünümün görünür olduğunu kontrol edin.

Sistem draw(_:)'ı ne sıklıkta çağırır?

Yalnızca gerekli olduğunda: ilk render, setNeedsDisplay() sonrası, contentMode = .redraw ile bounds değiştiğinde. Statik durumda draw(_:) tekrar çağrılmaz, CPU ve pil kaynaklarından tasarruf sağlar.

Swift'te super.draw(rect) çağırmak gerekli mi?

Apple, geçersiz kılınan yöntemin başında super.draw(rect) çağrısını önerir. Mevcut UIView uygulaması boş olsa da, super çağrısı gelecekteki UIKit sürümleriyle uyumluluğu garanti eder ve iyi bir uygulamadır.

Özet

  • draw(_:) / drawRect — Swift ve Objective-C'de UIView'in ana çizim yöntemi, sistem tarafından otomatik olarak çağrılır
  • CGContext — UIGraphicsGetCurrentContext() aracılığıyla draw(_:) içinde kullanılabilen Core Graphics bağlamı
  • setNeedsDisplay() — yeniden çizim istemenin doğru yolu; draw(_:)'ı doğrudan çağırmak yasaktır
  • Idempotentlik — doğru önbellekleme için draw(_:) aynı girdi verileriyle aynı sonucu üretmelidir
  • UIBezierPath — her çağrıda CPU yükünü en aza indirmek için draw(_:) dışında yollar oluşturun
  • rect parametresi — yeniden çizim alanını içerir; optimizasyon için kesişim kullanın — dışında çizmeyin
  • Profil oluşturma — yavaş işlemleri belirlemek için Instruments Core Animation aracılığıyla draw(_:) performansını kontrol edin

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun