draw(_:) / drawRect — је метода класе UIView (у Swift-у) и њен аналог у Objective-C-у (drawRect:), која је одговорна за приказивање садржаја прегледа коришћењем Core Graphics-а. Систем аутоматски позива ову методу приликом првог појављивања прегледа на екрану и након позива setNeedsDisplay(). Према Apple Documentation (2025), draw(_:) је једина метода у којој програмер има приступ графичком контексту тренутног екрана за прилагођено цртање. Преоптерећење draw(_:) даје потпуну контролу над изгледом компоненте — од једноставних геометријских облика до сложене анимиране графике.
Главно
draw(_:) — је метода инстанце UIView-а коју UIKit позива за приказивање садржаја прегледа. Унутар ове методе програмер добија приступ графичком контексту CGContext и користи API Core Graphics-а за цртање линија, попуна, текста и слика. drawRect: у Objective-C-у обавља исту функцију, али са другачијом синтаксом: једини параметар је CGRect који одређује област за поновно цртање.
Према Apple Engineering (2024), draw(_:) ради кроз CPU-рендеринг Bitmap Graphics Context-а, што обезбеђује максималну флексибилност, али захтева више ресурса у поређењу са CALayer-ом. Одлука о коришћењу draw(_:) доноси се на основу сложености графике и захтева перформанси.
У Swift-у метода се декларише као override func draw(_ rect: CGRect), где је rect правоугаоник који треба поново да се нацрта. У Objective-C-у потпис је - (void)drawRect:(CGRect)rect. Параметар rect може бити мањи од bounds прегледа при делимичном поновном цртању кроз setNeedsDisplay(_:).
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rect);
}
Систем аутоматски позива draw(_:) у строго одређеним сценаријима. Разумевање ових окидача помаже да се избегну непотребна поновна цртања и оптимизују перформансе прегледа. Испод су наведени сви случајеви аутоматског позива методе.
Apple документација упозорава: никада не позивајте draw(_:) директно. Систем сам одлучује када да изврши цртање, а директни позив нарушава унутрашњи механизам кеширања. За захтев за поновним цртањем увек користите setNeedsDisplay() или setNeedsDisplay(_:).
Преоптерећење draw(_:) у Swift-у почиње добијањем графичког контекста и накнадним позивима Core Graphics-а. Препоручује се креирање одвојених метода за логичке блокове цртања — то побољшава читљивост и тестираност кода.
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else { return }
// Параметри линије
context.setStrokeColor(UIColor.darkGray.cgColor)
context.setLineWidth(2.0)
// Цртање троугла
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()
}
У овом примеру draw(_:) црта троугао са тамно сивим контуром дебљине 2 пиксела. Позив super.draw(rect) на почетку методе препоручује Apple ради очувања родитељске логике цртања, иако је подразумевана имплементација draw(_:) у UIView-у празна.
Сваки позив draw(_:) треба да да идентичан резултат при истим улазним подацима. То омогућава систему да кешира резултат и не позива draw(_:) поново ако се садржај прегледа није променио. Немојте користити унутар draw(_:) случајне вредности, системско време или мрежне захтеве.
drawRect: — историјски прва верзија методе, која се појавила у iOS 2.0 заједно са Objective-C-ом. У Swift-у метода је преименована у draw(_:) са коришћењем спољног параметра _. Функционално методе су идентичне: обе примају CGRect области поновног цртања и користе UIGraphicsGetCurrentContext() за приступ графичком контексту.
| Карактеристика | draw(_:) (Swift) | drawRect: (Objective-C) |
|---|---|---|
| Потпис | override func draw(_ rect: CGRect) | - (void)drawRect:(CGRect)rect |
| Позив super | super.draw(rect) | [super drawRect:rect] |
| Контекст | UIGraphicsGetCurrentContext() | UIGraphicsGetCurrentContext() |
| Параметар rect | rect: CGRect | CGRect rect |
| Перформансе | Идентичне | Идентичне |
При миграцији пројекта са Objective-C на Swift, преименовање методе је један од првих задатака. Xcode пружа аутоматски конвертер, али drawRect: захтева ручно ажурирање на draw(_:). Према Apple (2024), Swift верзија draw(_:) је пожељнија за нове пројекте.
draw(_:) се извршава на CPU-у, а неоптимална имплементација може бити узрок пада фрејмова и ниских перформанси. Apple препоручује неколико проверених приступа за убрзање цртања.
Свака операција Core Graphics-а (move(to:), addLine(to:), strokePath) има додатне трошкове. Групишите операције и користите CGPath за сложене облике — путања се креира једном и поново користи при сваком позиву draw(_:).
UIBezierPath — је Objective-C омотач око CGPath-а који пружа једноставан API за креирање облика. Направите UIBezierPath унапред (нпр. у иницијализатору) и једноставно позовите fill() или stroke() унутар draw(_:).
private let starPath: UIBezierPath = {
let path = UIBezierPath()
// Изградња облика звезде
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(_:). Познавање ових образаца помаже да се избегну грешке и смањење перформанси. Размотримо најчешће проблеме и њихова решења.
Пратећи ова правила, обезбедићете стабилно и брзо цртање прилагођених прегледа у било ком iOS пројекту. Профилишите draw(_:) кроз Instruments (Core Animation) да бисте видели стварно време извршења и уска грла.
Често постављана питања
Не, директан позив draw(_:) је забрањен Apple документацијом. Систем сам управља циклусом цртања. За захтев поновног цртања користите setNeedsDisplay(), који исправно означава преглед као онај који захтева ажурирање у најближем циклусу рендеринга.
Функционално ове методе су идентичне. drawRect: се користи у Objective-C-у, draw(_:) — у Swift-у. Обе примају CGRect области поновног цртања и користе исти Core Graphics контекст кроз UIGraphicsGetCurrentContext().
Apple оптимизује рендеринг: ако UIView нема преоптерећен draw(_:), систем не креира битмап контекст за њега. То штеди меморију. Ако преоптерећење постоји, али се метода не позива — проверите да оквир прегледа није нула и да је преглед видљив.
Само када је потребно: прво рендеровање, након setNeedsDisplay(), при промени bounds са contentMode = .redraw. У статичном стању draw(_:) се не позива поново, што штеди ресурсе CPU-а и батерију.
Apple препоручује позивање super.draw(rect) на почетку преоптерећене методе. Иако је тренутна имплементација UIView-а празна, super позив обезбеђује компатибилност са будућим верзијама UIKit-а и добра је пракса.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође