setNeedsDisplay() — ito ay isang instance method ng UIView na minamarkahan ang view bilang nangangailangan ng muling pagguhit. Hindi tulad ng direktang pagtawag ng draw(_:), ang setNeedsDisplay() ay nagtatakda lamang ng dirty flag para sa view at agad na ibinabalik ang kontrol. Pinoproseso ng system ang kahilingang ito sa pinakamalapit na render cycle, na nagpapahintulot na pagsamahin ang maraming tawag sa isang operasyon ng pagguhit. Ayon sa Apple Documentation (2025), ang naantalang muling pagguhit sa pamamagitan ng setNeedsDisplay() ay ang tanging tamang paraan ng pag-update ng nilalaman ng custom na UIView.
Mga Pangunahing Punto
setNeedsDisplay() — ay isang UIView method na nagpapahiwatig sa system na ang nilalaman ng view ay luma na at nangangailangan ng muling pag-render. Ang pamamaraan ay hindi tumatanggap ng mga parameter at nagbabalik ng void. Pagkatapos ng tawag, ang view ay minamarkahan bilang dirty, at sa pinakamalapit na cycle ng pagguhit ay tinatawag ng system ang draw(_:) para sa view na ito.
Ang pangunahing tampok ay pagiging asinkrono. Ang maraming sunod-sunod na tawag ng setNeedsDisplay() para sa parehong view ay hindi magreresulta sa maraming tawag ng draw(_:) — pinagsasama sila ng system sa isang operasyon. Ito ay kritikal para sa pagganap: kung ang property ng view ay nagbago ng maraming beses bawat frame, ang draw(_:) ay tinatawag lamang nang isang beses.
Ang mekanismo ng naantalang muling pagguhit ay batay sa render cycle ng UIKit. Kapag tinawag ang setNeedsDisplay(), itinatakda ng system ang panloob na flag layer.needsDisplay sa true. Sa dulo ng kasalukuyang run loop, dumadaan ang system sa lahat ng dirty-layer at tinatawag ang draw(_:) para sa bawat isa.
Ang UIKit run loop ay may kasamang update phase, kung saan pinoproseso ang mga dirty view. Sa phase na ito, tinatawag ang layoutSubviews() kung kinakailangan, pagkatapos ay draw(_:) para sa lahat ng minarkahang view. Pagkatapos ng pagguhit, ang resulta ay ipinapadala sa GPU sa pamamagitan ng Core Animation para sa compositing.
class ProgressView: UIView {
var progress: CGFloat = 0 {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let ctx = UIGraphicsGetCurrentContext() else { return }
// Background
ctx.setFillColor(UIColor.lightGray.cgColor)
ctx.fill(rect)
// Progress 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)
}
}
Sa halimbawang ito, ina-update ng progressView ang progress, at ang bawat setter ay awtomatikong tumatawag ng setNeedsDisplay(). Hintayin ng system ang dulo ng run loop at tatawagin ang draw(_:) na may kasalukuyang halaga ng progress. Kung magbago ang progress nang tatlong beses sa isang frame, ang draw(_:) ay isasagawa lamang nang isang beses — gamit ang huling halaga.
Ang pamamaraang setNeedsDisplay(_:) ay tumatanggap ng parameter na rect ng uri ng CGRect, na naglilimita sa lugar ng muling pagguhit. Ito ay nagpapahintulot ng muling pagguhit lamang ng binagong bahagi ng view, hindi ang kabuuan. Ang pagkakaiba sa pagganap ay nagiging kapansin-pansin kapag nagtatrabaho sa malalaking view kung saan ang mga pagbabago ay nakakaapekto sa maliit na lugar.
| Katangian | setNeedsDisplay() | setNeedsDisplay(_:) |
|---|---|---|
| Parameter | Wala | CGRect — lugar ng muling pagguhit |
| Lugar ng muling pagguhit | Buong bounds ng view | Tanging tinukoy na parihaba |
| Pagganap | Mababa sa malalaking view | Mataas sa bahagyang pagbabago |
| Parameter rect sa draw(_:) | Buong bounds | Tinukoy na parihaba |
| Kailan gagamitin | Pagbabago ng buong nilalaman | Mga puntong pagbabago (cursor, highlight) |
Para sa kumplikadong graphics, inirerekomenda na iguhit muna ang buong eksena sa isang offscreen context, pagkatapos ay tawagin ang setNeedsDisplay(_:) para lamang sa binagong lugar. Ito ay isang karaniwang teknik sa mga application ng pagguhit at graphic editor sa iOS.
displayIfNeeded() — ay isang sabay-sabay na pamamaraan na agad na nag-uumpisa ng muling pagguhit ng lahat ng dirty view sa hierarchy, nang hindi naghihintay ng dulo ng run loop. Hindi tulad ng setNeedsDisplay() na nagtatakda lamang ng flag, pinipilit ng displayIfNeeded() ang agarang pagpapatupad ng draw(_:).
Inirerekomenda ng Apple na gamitin lamang ang displayIfNeeded() sa mga matinding kaso, kapag ang resulta ng pagguhit ay kailangan agad — halimbawa, bago gumawa ng screenshot o sa sabay-sabay na pagbuo ng imahe para sa UIGraphicsImageRenderer. Sa karaniwang mga sitwasyon, ang asinkronong modelo sa pamamagitan ng setNeedsDisplay() ay mas gusto dahil hindi nito hinaharangan ang main thread.
// Asinkrono — inirerekomenda
someView.setNeedsDisplay()
// Sabay-sabay — kung kinakailangan lamang
someView.setNeedsDisplay()
someView.displayIfNeeded() // draw(_:) tinawag agad
Ang pagtawag ng displayIfNeeded() nang walang naunang setNeedsDisplay() ay walang epekto — pinoproseso lamang ng pamamaraan ang mga view na minarkahan na bilang dirty. Kung walang view na nangangailangan ng muling pagguhit, ang displayIfNeeded() ay magtatapos nang hindi tumatawag ng draw(_:).
Ang madalas na tawag ng setNeedsDisplay() ay maaaring magpababa ng pagganap, lalo na sa panahon ng animation. Tingnan natin ang mga pangunahing estratehiya ng pag-optimize.
Sa halip na tawagin ang setNeedsDisplay() sa bawat pagbabago ng indibidwal na property, tipunin ang mga pagbabago at tawagin ang pamamaraan nang isang beses pagkatapos ilapat ang lahat ng update. Halimbawa, kapag binabago ang kulay, laki, at posisyon ng elemento — tawagin ang setNeedsDisplay() nang isang beses pagkatapos itakda ang lahat ng property.
Kung ang property ay maaaring i-animate sa pamamagitan ng CALayer (backgroundColor, opacity, position, transform), gamitin ang Core Animation sa halip na draw(_:). Ang mga property ng CALayer ay ina-update sa GPU nang hindi tumatawag ng draw(_:), na nagbibigay ng 60 FPS nang hindi naglo-load ng CPU.
Para sa paggrupo ng maraming pagbabago sa isang daanan ng render, gamitin ang CATransaction. Ito ay nagpapahintulot na pagsamahin ang maraming setNeedsDisplay() sa isang operasyon ng draw(_:) sa dulo ng transaksyon.
CATransaction.begin()
CATransaction.setDisableActions(true)
view1.setNeedsDisplay()
view2.setNeedsDisplay()
view3.setNeedsDisplay()
CATransaction.commit()
Huwag abusuhin ang displayIfNeeded() — hinaharangan ng sabay-sabay na muling pagguhit ang main thread at maaaring maging sanhi ng pagbaba ng frame. Gamitin lamang ito para sa mga operasyon kung saan ang resulta ng pagguhit ay kritikal bago matapos ang kasalukuyang run loop.
Mga Madalas Itanong
Hindi, ang direktang pagtawag ng draw(_:) ay ipinagbabawal. Tamang minamarkahan ng setNeedsDisplay() ang view bilang dirty, at tinatawag ng system ang draw(_:) sa tamang sandali ng render cycle. Ang direktang pagtawag ng draw(_:) ay binabalewala ang mekanismo ng caching at maaaring humantong sa hindi pare-parehong estado.
Maraming tawag ng setNeedsDisplay() para sa parehong view ay pinagsasama ng system sa isang tawag ng draw(_:). Ito ay nangyayari dahil ang pamamaraan ay nagtatakda lamang ng dirty flag, na nire-reset lamang pagkatapos ng aktwal na pagpapatupad ng draw(_:) sa dulo ng run loop.
setNeedsDisplay() ay humihiling ng muling pagguhit ng nilalaman ng view (tawag ng draw(_:)). setNeedsLayout() ay humihiling ng muling pag-aayos ng mga subview (tawag ng layoutSubviews()). Ang layoutSubviews() ay maaaring humantong sa pagbabago ng laki, na maaaring magdulot ng muling pagguhit.
Ang setNeedsDisplay(_:) ay dapat gamitin sa mga puntong pagbabago: paggalaw ng cursor, pagbabago ng kulay ng napiling lugar, pag-update ng bahagi ng graph. Nililimitahan nito ang lugar ng muling pagguhit at pinapataas ang pagganap kumpara sa buong muling pagguhit ng buong view.
Bilang default, ang pagbabago ng frame o bounds ay hindi tumatawag ng setNeedsDisplay(). Inililipat lamang ng system ang view. Kung kailangan ang muling pagguhit sa pagbabago ng laki, itakda ang property na contentMode sa halagang .redraw — pagkatapos ay awtomatikong tatawag ang UIKit ng setNeedsDisplay() sa bawat pagbabago ng bounds.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din