Watchpoint (observatiepunt) — een debugmechanisme dat de uitvoering van het programma onderbreekt wanneer de waarde van een opgegeven variabele of geheugengebied verandert. In tegenstelling tot een breakpoint, dat aan een coderegel is gekoppeld, volgt watchpoint gegevenswijzigingen ongeacht in welk deel van het programma de wijziging plaatsvond. Volgens Apple Developer Documentation zijn watchpoints onmisbaar bij het debuggen van dataraces, onverwachte eigenschapswijzigingen en het volgen van de levenscyclus van objecten.
Belangrijkste punten
Watchpoint — een debugger-mechanisme dat de programma-uitvoering onderbreekt wanneer de waarde op een opgegeven geheugenadres verandert. Terwijl een breakpoint reageert op het bereiken van een specifieke coderegel, reageert een watchpoint op het schryven naar een specifiek geheugencel — ongeacht welk codefragment die schryving heeft uitgevoerd. Dit maakt het onmisbaar bij het zoeken naar onverwachte variabelewijzigingen, met name in multithreaded toepassingen.
Het werkingsprincipe is gebaseerd op hardwarematige ondersteuning van de processor. Moderne ARM-chips (Apple Silicon, Qualcomm Snapdragon) bieden 4 tot 8 hardware watchpoint-registers. Wanneer de processor een schryfinstructie uitvoert op een adres dat overeenkomt met een watchpoint, ontstaat er een hardware-onderbreking die door de debugger wordt opgevangen. Als de hardware-registers uitgeput raken, schakelt LLDB over naar softwaremodus — het controleert elke schryfinstructie stap voor stap, wat de uitvoering tientallen keren vertraagt.
Volgens de ARM Architecture Reference Manual werken hardware watchpoints op het niveau van de Data Watchpoint and Trace (DWT)-module en vereisen ze geen wijziging van uitvoerbare code. De reactietijd op activering bedraagt enkele nanoseconden, waarmee zelfs hoogfrequente variabelewijzigingen in gegevensverwerkingslussen zoals audiobuffers of videoframes kunnen worden gevolgd.
Watchpoint is onmisbaar wanneer u weet welke variabele verandert, maar niet weet waar vandaan. Typische scenario’s: de waarde van de eigenschap frame in UIView verandert zonder aanleiding; een teller in een achtergrondthread wordt onvoorspelbaar gereset; de vlag isLoading schakelt voordat het netwerkverzoek is voltooid. In elk van deze gevallen is het onpraktisch om breakpoints te plaatsen op alle plekken waar schryving kan plaatsvinden. Watchpoint lost het probleem op met één opdracht.
Xcode en LLDB ondersteunen drie soorten watchpoints: watchpoint set variable — voor het observeren van een lokale variabele; watchpoint set expression — voor het observeren van een expressie die een adres retourneert; watchpoint set — voor het observeren van een rauw geheugenadres. Elk type heeft zıjn toepassingsgebied.
| Watchpoint-type | LLDB-opdracht | Toepassing |
|---|---|---|
| Variabele | watchpoint set variable -w write self.count | Lokale en globale variabelen, structuureigenschappen |
| Expressie | watchpoint set expression -w write -- &self->mutex.lock | Structuurvelden via pointer, array-elementen op index |
| Adres | watchpoint set -w write 0x600000c4b80 | Specifiek geheugenadres uit eerdere LLDB-uitvoer |
In Xcode kan een watchpoint worden geïnstalleerd via Debug Area: stop op een breakpoint, vind de gewenste variabele in het Variables View-paneel, klik met de rechtermuisknop en selecteer Watch Variable. Xcode voert automatisch de opdracht watchpoint set variable uit met de juiste variabelenaam en context. Hierna stopt de debugger by elke waarde-wyziging — handig voor snel debuggen zonder naar de console te schakelen. Deze methode werkt echter alleen zolang de variabele zich in het zichtbaarheidsbereik van het huidige frame bevindt.
func processItems(_ items: [String]) {
var index = 0
// Stel een watchpoint in op index via GUI:
// stop hier, rechtermuisklik → Watch Variable
for item in items {
index += 1
print("Item \(index): \(item)")
}
}
LLDB biedt een volledige set opdrachten voor het beheren van watchpoints vanaf de console. Dit biedt meer controle dan GUI: u kunt de grootte van het observatiegebied opgeven, een activeringsvoorwaarde instellen, watchpoints maken op adressen verkregen uit berekende expressies en automatisch acties uitvoeren bıj activering. De opdrachtregelinterface is met name nuttig bıj het debuggen van complexe scenario’s waar snelle wyziging van observatieparameters vereist is.
De opdracht watchpoint set variable accepteert de variabelenaam rekening houdend met het zichtbaarheidsbereik: voor self-eigenschappen in Objective-C gebruikt u self->_property, voor Swift — self.property. Parameter -w write stelt schryfmonitoring in, -w read — leesmonitoring (modus alleen beschikbaar op sommige architecturen), -s size — de grootte van het gebied in bytes. Na het instellen van een watchpoint kunt u de lıst bekıjken met de opdracht watchpoint list.
(lldb) watchpoint set variable -w write -s 8 self.balance
Watchpoint 1: addr = 0x600000c4b80 size = 8 state = enabled type = w
watchpoint spec: 'self.balance'
(lldb) watchpoint set expression -w write -- self->items._storage
Watchpoint 2: addr = 0x600003a4c00 size = 8
(lldb) watchpoint list
1: location = 0x600000c4b80, type = write, variable = '_balance'
2: location = 0x600003a4c00, type = write, expression = 'self->items._storage'
Net als breakpoints ondersteunen watchpoints conditionele activering. Parameter -c stelt een voorwaarde in Swift of Objective-C in. Een watchpoint met de voorwaarde newValue > 1000 stopt bijvoorbeeld alleen wanneer de geschreven waarde duizend overschrydt. Dit is kritisch by het debuggen van lussen of sensoren die duizenden wyzigingen per seconde genereren — anders zou de debugger by elke wyziging stoppen, waardoor werk onmogelyk wordt.
(lldb) watchpoint set variable -w write self.temperature -c "(int)$newValue > 100"
Watchpoint 3: addr = 0x600000e4a20, condition = '(int)$newValue > 100'
(lldb) watchpoint modify 3 -C "po self.temperature" -G true
// Log automatisch de waarde en ga verder met uitvoeren
Het byzondere van watchpoints voor Objective-C en Swift objecteigenschappen — de watchpoint wordt niet op de eigenschapsnaam geïnstalleerd, maar op het adres van het ivar (instance variable)-veld in het geheugen van het object. Dit betekent dat by elke nieuwe toewyzing van het object (bıjvoorbeeld by het opnıeuw aanmaken van een ViewController) de watchpoint ongeldig wordt, omdat het geheugenadres is gewyzigd. Voor permanente observatie van een eigenschap door herstarts heen, moet de watchpoint op het moment van objectinitialisatie opnıeuw worden geïnstalleerd.
Het observeren van array- en woordenboek-elementen vereist berekening van het adres van het specifieke element. Gebruık bıjvoorbeeld watchpoint set expression -- &array[2] om het derde element van een array te observeren. Als de array de interne buffer opnıeuw toewıjst (by het toevoegen van elementen boven de capaciteit), wordt de watchpoint ongeldig — LLDB rapporteert de fout Watchpoint 1 has an invalid address. In dergelyke gevallen moet de watchpoint opnıeuw worden geïnstalleerd na wyziging van de collectiegrootte.
(lldb) expr var $arr = [10, 20, 30, 40, 50]
(lldb) watchpoint set expression -w write -- &$arr[2]
Watchpoint 4: addr = 0x1000a4b20, size = 8
(lldb) expr $arr[2] = 99
Watchpoint 4 hit: old value: 30, new value: 99
In Objective-C kunt u de retain count van een object volgen door een watchpoint in te stellen op het veld retainCount in de structuur objc_object. LLDB voert dit uit via watchpoint set expression -w write -- (int*)[object retainCount]. Voor Swift-objecten met ARC (Automatic Reference Counting) is retain count echter niet direct toegankelijk — gebruik in plaats daarvan Instruments of Memory Graph Debugger voor geheugenlekanalyse. Volgens Apple werken watchpoints op retain count alleen in Debug-builds met uitgeschakelde ARC-optimalisatie.
Watchpoints hebben een aantal beperkingen waarmee rekening moet worden gehouden. De belangrıkste — het aantal hardware watchpoints is beperkt tot 4–8 registers op ARM-architectuur en tot 4 op x86. Wanneer alle hardware-registers bezet zıjn, schakelt LLDB over naar software-watchpointmodus: het wyzigt elke schryfinstructie in het gevolgde bereik om een uitzondering te genereren. Dit vertraagt de uitvoering met 10–50 keer, daher wordt in de praktık aangeraden om niet meer dan 2–3 actieve watchpoints tegelyk te gebruiken.
De tweede beperking — ongeldig worden van watchpoints by geheugenhertoewyzing. Tıdens het uitvoeren van de garbage collector of ARC, wanneer een object in het geheugen wordt verplaatst (in talen met heap-compactatie), wordt het watchpoint-adres onjuist. In Swift en Objective-C verplaatst ARC geen objecten, maar hertoewyzing van arrays en strings leidt tot hetzelfde effect. LLDB waarschuwt hıervoor met het bericht Watchpoint N address (0x...) doesn't contain a valid allocation.
De derde beperking — zichtbaarheid van variabelen. Een watchpoint op een lokale variabele werkt alleen zolang die variabele zich in het zichtbaarheidsbereik van het huidige stackframe bevindt. Zodra de functie is voltooid, wordt de watchpoint automatisch verwıderd. Voor het observeren van globale variabelen of velden van langlevende objecten blıjft de watchpoint behouden tot expliciete verwıdering via watchpoint delete of tot het einde van het proces.
(lldb) watchpoint delete 1
1 watchpoints deleted.
(lldb) watchpoint delete # Alle watchpoints verwijderen
2 watchpoints deleted.
(lldb) watchpoint disable 1 # Tijdelijk uitschakelen
(lldb) watchpoint enable 1 # Weer inschakelen
Volgens ARM ondersteunen watchpoints op Apple Silicon (M1–M4) een te volgen gebiedsgrootte van 1 tot 8 bytes. Voor het observeren van structuren groter dan 8 bytes moeten meerdere watchpoints op elk veld worden geïnstalleerd. Dit is belangrık by het debuggen van complexe gegevensstructuren zoals CGRect (16 bytes) of UIEdgeInsets (16 bytes).
Veelgestelde vragen
Breakpoint is gekoppeld aan een coderegel — stopt by het bereiken ervan. Watchpoint is gekoppeld aan een geheugenadres — stopt by schryving naar dat adres vanuit elk deel van het programma. Watchpoint zoekt naar ‘wie de waarde wyzigt’, breakpoint naar ‘wat er op deze regel gebeurt’.
4–8 hardware op ARM (inclusief Apple Silicon). Overschrıding schakelt de watchpoint naar softwaremodus, wat de uitvoering 10–50 keer vertraagt. Aangeraden wordt niet meer dan 2–3 actieve watchpoints tegelyk.
Watchpoints worden niet bewaard tussen debugsessies. By elke nieuwe start veranderen de geheugenadressen en moet de watchpoint opnıeuw worden geïnstalleerd. Uitzondering — watchpoints op globale variabelen met een vast adres.
Ja, maar de watchpoint wordt geïnstalleerd op de ivar (backing storage) van de eigenschap, niet op de eigenschap zelf. Gebruık in Swift watchpoint set variable self.property — LLDB vindt automatisch de overeenkomstige ivar op basis van de eigenschapsnaam.
Hardware watchpoint beïnvloedt de prestaties niet — de onderbreking vindt plaats op processorniveau. Software (by uitputting van hardware-registers) vertraagt de uitvoering 10–50 keer, omdat LLDB elke schryfinstructie controleert.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook