setNeedsDisplay(): metodens essens och omritningsmekanism i iOS

Författare: IT Sectr Publicerad: 2026-07-20 Lästid: 6 min

setNeedsDisplay() — är en instansmetod för UIView som markerar en vy som behöver omritning. Till skillnad från direkt anrop av draw(_:), sätter setNeedsDisplay() bara en dirty-flagga för vyn och återlämnar kontrollen omedelbart. Systemet behandlar denna begäran i närmaste renderingscykel, vilket gör det möjligt att slå samman flera anrop till en ritoperation. Enligt Apple Documentation (2025) är uppskjuten omritning via setNeedsDisplay() det enda korrekta sättet att uppdatera innehållet i en anpassad UIView.

Huvudpunkter

  • setNeedsDisplay() — uppskjuten begäran om omritning av UIView, anropar inte draw(_:) synkront
  • dirty flag — intern flagga för vyn som sätts av setNeedsDisplay() och återställs efter draw(_:)
  • setNeedsDisplay(_:) — överlagring med CGRect för partiell omritning av endast angivet område
  • displayIfNeeded() — påtvingad synkron omritning, används för omedelbar uppdatering
  • Renderingscykel — systemet behandlar dirty-vyer i slutet av run loop, sammanfogar flera begäranden till en genomgång

Vad är setNeedsDisplay()

setNeedsDisplay() — är en UIView-metod som signalerar till systemet att vyens innehåll är föråldrat och kräver omrendering. Metoden tar inga parametrar och returnerar void. Efter anropet markeras vyn som dirty, och i närmaste ritcykel anropar systemet draw(_:) för denna vy.

Den viktigaste egenskapen är asynkronicitet. Flera på varandra följande anrop av setNeedsDisplay() för samma vy leder inte till flera anrop av draw(_:) — systemet slår samman dem till en operation. Detta är kritiskt för prestanda: om en vyegenskap ändras flera gånger per bildruta anropas draw(_:) endast en gång.

Hur uppskjuten omritning fungerar

Mekanismen för uppskjuten omritning baseras på UIKit-renderingscykeln. När setNeedsDisplay() anropas sätter systemet den interna flaggan layer.needsDisplay till true. I slutet av den aktuella run loop går systemet igenom alla dirty-lager och anropar draw(_:) för varje.

Run loop och renderingssteg

UIKit run loop inkluderar update-fasen, under vilken dirty-vyer bearbetas. I denna fas anropas layoutSubviews() vid behov, därefter draw(_:) för alla markerade vyer. Efter ritningen överförs resultatet till GPU via Core Animation för kompositering.

swift
class ProgressView: UIView {
    var progress: CGFloat = 0 {
        didSet {
            setNeedsDisplay()
        }
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        guard let ctx = UIGraphicsGetCurrentContext() else { return }

        // Bakgrund
        ctx.setFillColor(UIColor.lightGray.cgColor)
        ctx.fill(rect)

        // Förloppsindikator
        let fillRect = CGRect(x: rect.minX, y: rect.minY,
                              width: rect.width * progress, height: rect.height)
        ctx.setFillColor(UIColor.systemGreen.cgColor)
        ctx.fill(fillRect)
    }
}

I detta exempel uppdaterar progressView progress, och varje setter anropar automatiskt setNeedsDisplay(). Systemet väntar på slutet av run loop och anropar draw(_:) med det aktuella värdet för progress. Om progress ändras tre gånger i en bildruta, körs draw(_:) endast en gång — med det sista värdet.

setNeedsDisplay() vs setNeedsDisplay(_:)

Metoden setNeedsDisplay(_:) accepterar en parameter rect av typen CGRect, som begränsar omritningsområdet. Detta gör det möjligt att endast rita om den ändrade delen av vyn, inte hela. Skillnaden i prestanda blir märkbar vid arbete med stora vyer där förändringar påverkar ett litet område.

EgenskapsetNeedsDisplay()setNeedsDisplay(_:)
ParameterNejCGRect — omritningsområde
OmritningsområdeHela vyns boundsEndast angiven rektangel
PrestandaLägre vid stora vyerHögre vid partiella ändringar
Parameter rect i draw(_:)Hela boundsAngiven rektangel
När användaÄndring av hela innehålletPunktvisa ändringar (markör, highlight)

För komplex grafik rekommenderas att först rita hela scenen i en offscreen-kontext och sedan anropa setNeedsDisplay(_:) endast för det ändrade området. Detta är en standardteknik i ritapplikationer och grafiska redigerare på iOS.

displayIfNeeded() kontra setNeedsDisplay()

displayIfNeeded() — är en synkron metod som omedelbart startar omritning av alla dirty-vyer i hierarkin, utan att vänta på slutet av run loop. Till skillnad från setNeedsDisplay() som bara sätter en flagga, tvingar displayIfNeeded() omedelbar körning av draw(_:).

Apple rekommenderar att använda displayIfNeeded() endast i extrema fall, när ritresultatet behövs omedelbart — till exempel före skapande av skärmdump eller vid synkron generering av bild för UIGraphicsImageRenderer. I vanliga scenarier är den asynkrona modellen via setNeedsDisplay() att föredra eftersom den inte blockerar huvudtråden.

swift
    // Asynkron — rekommenderas
someView.setNeedsDisplay()

    // Synkron — endast vid behov
someView.setNeedsDisplay()
someView.displayIfNeeded() // draw(_:) anropades omedelbart

Anrop av displayIfNeeded() utan föregående setNeedsDisplay() ger ingen effekt — metoden bearbetar endast vyer som redan markerats som dirty. Om ingen vy kräver omritning avslutas displayIfNeeded() utan att anropa draw(_:).

Optimering av anrop till setNeedsDisplay()

Frekventa anrop av setNeedsDisplay() kan minska prestandan, särskilt under animering. Låt oss titta på de viktigaste optimeringsstrategierna.

Sammanfogning av ändringar via modell

Istället för att anropa setNeedsDisplay() vid varje ändring av en enskild egenskap, samla ändringarna och anropa metoden en gång efter att alla uppdateringar har tillämpats. Till exempel vid ändring av färg, storlek och position för ett element — anropa setNeedsDisplay() en gång efter att alla egenskaper har ställts in.

Användning av CALayer för animerbara egenskaper

Om en egenskap kan animeras via CALayer (backgroundColor, opacity, position, transform), använd Core Animation istället för draw(_:). CALayer-egenskaper uppdateras på GPU utan att anropa draw(_:), vilket ger 60 FPS utan CPU-belastning.

Batchuppdatering via CATransaction

För att gruppera flera ändringar i en renderingsgenomgång, använd CATransaction. Detta gör det möjligt att slå samman flera setNeedsDisplay() till en draw(_:)-operation i slutet av transaktionen.

swift
CATransaction.begin()
CATransaction.setDisableActions(true)

view1.setNeedsDisplay()
view2.setNeedsDisplay()
view3.setNeedsDisplay()

CATransaction.commit()

Missbruka inte displayIfNeeded() — synkron omritning blockerar huvudtråden och kan orsaka bildrutefall. Använd det endast för operationer där ritresultatet är kritiskt före slutet av den aktuella run loop.

Vanliga frågor

Kan draw(_:) anropas direkt istället för setNeedsDisplay()?

Nej, direkt anrop av draw(_:) är förbjudet. setNeedsDisplay() markerar vyn korrekt som dirty, och systemet anropar draw(_:) vid rätt tillfälle i renderingscykeln. Direkt anrop av draw(_:) ignorerar cachelagringsmekanismen och kan leda till inkonsekvent tillstånd.

Vad händer vid flera anrop av setNeedsDisplay()?

Flera anrop av setNeedsDisplay() för samma vy slås samman av systemet till ett anrop av draw(_:). Detta beror på att metoden bara sätter dirty flag, som återställs först efter faktisk körning av draw(_:) i slutet av run loop.

Vad skiljer setNeedsDisplay() från setNeedsLayout()?

setNeedsDisplay() begär omritning av vyens innehåll (anrop av draw(_:)). setNeedsLayout() begär omplacering av subviews (anrop av layoutSubviews()). layoutSubviews() kan leda till storleksändring, vilket i sin tur kan orsaka omritning.

När ska setNeedsDisplay(_:) användas?

setNeedsDisplay(_:) bör användas vid punktvisa ändringar: markörrörelse, färgändring av markerat område, uppdatering av del av graf. Detta begränsar omritningsområdet och ökar prestandan jämfört med full omritning av hela vyn.

Utlöser ändring av frame automatiskt setNeedsDisplay()?

Som standard utlöser ändring av frame eller bounds inte setNeedsDisplay(). Systemet flyttar bara vyn. Om omritning krävs vid storleksändring, ställ in egenskapen contentMode till värdet .redraw — då kommer UIKit automatiskt att anropa setNeedsDisplay() vid varje ändring av bounds.

Sammanfattning

  • setNeedsDisplay() — asynkron UIView-metod för att begära uppskjuten omritning genom att sätta dirty-flagga
  • setNeedsDisplay(_:) — överlagring med CGRect för partiell omritning av endast angivet område, optimerar prestanda
  • displayIfNeeded() — synkron metod för omedelbar omritning av dirty-vyer, används endast vid yttersta nödfall
  • Run loop — systemet behandlar dirty-vyer i slutet av aktuell cykel och slår samman flera anrop till en draw(_:)-genomgång
  • CALayer — för animerbara egenskaper (position, opacity) använd Core Animation istället för draw(_:) — detta är vida effektivare
  • CATransaction — grupperar flera ändringar i en renderingscykel, minskar antalet draw(_:)-anrop
  • contentMode = .redraw — aktiverar automatiskt anrop av setNeedsDisplay() när vyens bounds ändras

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också