Watchpoint — co to jest, rodzaje i konfiguracja punktów obserwacyjnych w Xcode

Autor: IT Sectr Opublikowano: 2026-05-07 Czas czytania: 8 min

Watchpoint (punkt obserwacyjny) — mechanizm debugowania, który wstrzymuje wykonanie programu przy zmianie wartości wskazanej zmiennej lub obszaru pamięci. W przeciwieństwie do breakpointa, który jest przypisany do linii kodu, watchpoint śledzi zmianę danych niezależnie od tego, w którym miejscu programu nastąpiła modyfikacja. Według Apple Developer Documentation, watchpointy są niezastąpione podczas debugowania wyścigów danych, nieoczekiwanych zmian właściwości i śledzenia cyklu życia obiektów.

Najważniejsze

  • Watchpoint — punkt obserwacyjny zmiany zmiennej, uruchamiany przy każdym zapisie we wskazany obszar pamięci.
  • Xcode obsługuje watchpointy przez GUI i konsolę LLDB, w tym warunkowe punkty obserwacyjne.
  • Zmienne właściwości obiektów wymagają watchpointa z podaniem adresu pamięci, a nie nazwy zmiennej.
  • Wydajność z watchpointami znacznie spada z powodu sprzętowego monitorowania każdej operacji zapisu.
  • Watchpointy nie są przechowywane między sesjami debugowania — trzeba je ustawiać ponownie po każdym uruchomieniu.

Co to jest watchpoint i zasada działania

Watchpoint — to mechanizm debuggera, który wstrzymuje wykonanie programu, gdy wartość pod wskazanym adresem pamięci ulegnie zmianie. Jeśli breakpoint reaguje na osiągnięcie określonej linii kodu, to watchpoint reaguje na zapis w określoną komórkę pamięci — niezależnie od tego, który fragment kodu ten zapis wykonał. To czyni go niezastąpionym przy poszukiwaniu nieoczekiwanych modyfikacji zmiennych, szczególnie w aplikacjach wielowątkowych.

Zasada działania opiera się na wsparciu sprzętowym procesora. Nowoczesne układy ARM (Apple Silicon, Qualcomm Snapdragon) udostępniają od 4 do 8 sprzętowych rejestrów watchpoint. Gdy procesor wykonuje instrukcję zapisu pod adresem zgodnym z watchpointem, powstaje przerwanie sprzętowe, które przechwytuje debugger. Jeśli rejestry sprzętowe się wyczerpią, LLDB przełącza się w tryb programowy — krok po kroku sprawdza każdą instrukcję zapisu, co spowalnia wykonanie dziesięciokrotnie.

Według ARM Architecture Reference Manual, sprzętowe watchpointy działają na poziomie modułu Data Watchpoint and Trace (DWT) i nie wymagają modyfikacji kodu wykonywalnego. Czas reakcji na uruchomienie wynosi jednostki nanosekund, co pozwala śledzić nawet wysokoczęstotliwościowe zmiany zmiennych w pętlach przetwarzania danych, takich jak bufory audio czy klatek wideo.

Kiedy watchpoint jest skuteczniejszy od breakpointa

Watchpoint jest niezastąpiony, gdy wiesz, która zmienna się zmienia, ale nie wiesz skąd. Typowe scenariusze: wartość właściwości frame w UIView zmienia się bez widocznej przyczyny; licznik w wątku tła resetuje się nieprzewidywalnie; flaga isLoading przełącza się wcześniej niż zakończyło się żądanie sieciowe. W każdym z tych przypadków ustawianie breakpointa we wszystkich miejscach, gdzie może nastąpić zapis, jest niepraktyczne. Watchpoint rozwiązuje problem jednym poleceniem.

Rodzaje watchpointów i sposoby ustawiania

Xcode i LLDB obsługują trzy typy watchpointów: watchpoint set variable — do obserwacji zmiennej lokalnej; watchpoint set expression — do obserwacji wyrażenia zwracającego adres; watchpoint set — do obserwacji surowego adresu pamięci. Każdy typ ma swój obszar zastosowania.

Typ watchpointaPolecenie LLDBZastosowanie
Zmiennawatchpoint set variable -w write self.countZmienne lokalne i globalne, właściwości struktur
Wyrażeniewatchpoint set expression -w write -- &self->mutex.lockPola struktur przez wskaźnik, elementy tablic po indeksie
Adreswatchpoint set -w write 0x600000c4b80Konkretny adres pamięci z poprzedniego wyjścia LLDB

Ustawianie przez GUI Xcode

W Xcode watchpoint można ustawić przez Debug Area: zatrzymaj się na breakpoincie, znajdź potrzebną zmienną w panelu Variables View, kliknij prawym przyciskiem i wybierz Watch Variable. Xcode automatycznie wykona polecenie watchpoint set variable z poprawną nazwą zmiennej i kontekstem. Następnie debugger będzie zatrzymywał się przy każdej zmianie wartości — wygodne do szybkiego debugowania bez przełączania do konsoli. Jednak ta metoda działa tylko gdy zmienna znajduje się w zasięgu widoczności bieżącej ramki.

swift
func processItems(_ items: [String]) {
    var index = 0
    // Ustaw watchpoint na index przez GUI:
    // zatrzymaj się tutaj, kliknij prawym przyciskiem → Watch Variable
    for item in items {
        index += 1
        print("Item \(index): \(item)")
    }
}

Zarządzanie watchpointami przez LLDB

LLDB udostępnia pełen zestaw poleceń do zarządzania watchpointami z konsoli. Daje to większą kontrolę niż GUI: można określać rozmiar obszaru obserwacji, ustawiać warunek uruchomienia, tworzyć watchpointy na adresy uzyskane z obliczonych wyrażeń i automatycznie wykonywać akcje przy uruchomieniu. Interfejs wiersza poleceń jest szczególnie przydatny podczas debugowania złożonych scenariuszy, gdzie trzeba szybko zmieniać parametry obserwacji.

Podstawowe polecenia watchpoint

Polecenie watchpoint set variable przyjmuje nazwę zmiennej z uwzględnieniem zakresu widoczności: dla właściwości self w Objective-C używaj self->_property, dla Swift — self.property. Parametr -w write ustawia śledzenie zapisu, -w read — odczytu (tryb dostępny tylko na niektórych architekturach), -s size — rozmiar obszaru w bajtach. Po ustawieniu watchpointa można wyświetlić listę poleceniem watchpoint list.

lldb
(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'

Warunkowe watchpointy

Podobnie jak breakpointy, watchpointy obsługują warunkowe uruchamianie. Parametr -c określa warunek w Swift lub Objective-C. Na przykład watchpoint z warunkiem newValue > 1000 zatrzyma się tylko gdy zapisywana wartość przekroczy tysiąc. Jest to krytyczne przy debugowaniu pętli lub czujników generujących tysiące zmian na sekundę — w przeciwnym razie debugger zatrzymywałby się przy każdej zmianie, uniemożliwiając pracę.

lldb
(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
// Automatycznie loguj wartość i kontynuuj wykonanie

Watchpointy dla właściwości obiektów i kolekcji

Osobliwość watchpointów dla właściwości obiektów Objective-C i Swift — watchpoint ustawia się nie na nazwę właściwości, ale na adres pola ivar (instance variable) w pamięci obiektu. Oznacza to, że przy każdym nowym przydzieleniu obiektu (np. przy odtwarzaniu ViewController) watchpoint staje się nieaktualny, ponieważ adres pamięci się zmienił. Do stałej obserwacji właściwości przez restarty wymagane jest ponowne ustawienie watchpointa w momencie inicjalizacji obiektu.

Watchpoint na elementy kolekcji

Obserwacja elementów tablic i słowników wymaga obliczenia adresu konkretnego elementu. Na przykład do obserwacji trzeciego elementu tablicy użyj watchpoint set expression -- &array[2]. Jeśli tablica ponownie przydzieli wewnętrzny bufor (przy dodawaniu elementów powyżej capacity), watchpoint stanie się nieaktualny — LLDB zgłosi błąd Watchpoint 1 has an invalid address. W takich przypadkach trzeba ponownie ustawić watchpoint po zmianie rozmiaru kolekcji.

lldb
(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

Śledzenie retain count przez watchpoint

W Objective-C można śledzić retain count obiektu, ustawiając watchpoint na pole retainCount w strukturze objc_object. LLDB wykonuje to przez watchpoint set expression -w write -- (int*)[object retainCount]. Jednak dla obiektów Swift z ARC (Automatic Reference Counting) retain count nie jest bezpośrednio dostępny — zamiast tego używaj Instruments lub Memory Graph Debugger do analizy wycieków. Według Apple, watchpointy na retain count działają tylko w kompilacjach Debug z wyłączoną optymalizacją ARC.

Ograniczenia i wydajność watchpointów

Watchpointy mają szereg ograniczeń, które należy uwzględnić. Główne — liczba sprzętowych watchpointów jest ograniczona do 4–8 rejestrów w architekturze ARM i do 4 w x86. Gdy wszystkie rejestry sprzętowe są zajęte, LLDB przełącza się w tryb programowego watchpointa: modyfikuje każdą instrukcję zapisu w śledzonym zakresie, aby wygenerować wyjątek. Spowalnia to wykonanie 10–50 razy, dlatego w praktyce zaleca się używanie nie więcej niż 2–3 aktywnych watchpointów jednocześnie.

Drugie ograniczenie — nieaktualność watchpointów przy ponownym przydzielaniu pamięci. Podczas działania garbage collectora lub ARC, gdy obiekt jest przenoszony w pamięci (w językach z kompakcją sterty), adres watchpointa staje się nieprawidłowy. W Swift i Objective-C ARC nie przenosi obiektów, ale realokacja tablic i łańcuchów prowadzi do tego samego efektu. LLDB ostrzega o tym komunikatem Watchpoint N address (0x...) doesn't contain a valid allocation.

Trzecie ograniczenie — widoczność zmiennych. Watchpoint na zmienną lokalną działa tylko dopóki ta zmienna znajduje się w zasięgu widoczności bieżącej ramki stosu. Po zakończeniu funkcji watchpoint jest automatycznie usuwany. Do obserwacji zmiennych globalnych lub pól długożyciowych obiektów watchpoint pozostaje aktywny do jawnego usunięcia przez watchpoint delete lub do zakończenia procesu.

lldb
(lldb) watchpoint delete 1
1 watchpoints deleted.
(lldb) watchpoint delete               # Usuń wszystkie watchpoints
2 watchpoints deleted.
(lldb) watchpoint disable 1             # Tymczasowo wyłącz
(lldb) watchpoint enable 1              # Włącz ponownie

Według ARM, watchpointy na Apple Silicon (M1–M4) obsługują rozmiar śledzonego obszaru od 1 do 8 bajtów. Do obserwacji struktur o rozmiarze większym niż 8 bajtów wymagane jest ustawienie kilku watchpointów na każde pole. Jest to ważne przy debugowaniu złożonych struktur danych, takich jak CGRect (16 bajtów) czy UIEdgeInsets (16 bajtów).

Często zadawane pytania

Jaka jest różnica między watchpointem a breakpointem?

Breakpoint jest przypisany do linii kodu — zatrzymuje po jej osiągnięciu. Watchpoint jest przypisany do adresu pamięci — zatrzymuje przy zapisie pod ten adres z dowolnego miejsca programu. Watchpoint szuka „kto zmienia wartość", breakpoint — „co się dzieje w tej linii".

Ile watchpointów można ustawić jednocześnie?

4–8 sprzętowych na ARM (w tym Apple Silicon). Przekroczenie przełącza watchpoint w tryb programowy, co spowalnia wykonanie 10–50 razy. Zaleca się nie więcej niż 2–3 aktywne watchpointy jednocześnie.

Dlaczego watchpoint przestał działać po ponownym uruchomieniu aplikacji?

Watchpointy nie są przechowywane między sesjami debugowania. Przy każdym nowym uruchomieniu adresy pamięci się zmieniają i watchpoint trzeba ustawić ponownie. Wyjątkiem są watchpointy na zmienne globalne o stałym adresie.

Czy można ustawić watchpoint na właściwość Swift?

Tak, ale watchpoint ustawia się na ivar (backing storage) właściwości, a nie na samą właściwość. W Swift użyj watchpoint set variable self.property — LLDB automatycznie znajdzie odpowiedni ivar po nazwie właściwości.

Jak watchpoint wpływa na wydajność aplikacji?

Sprzętowy watchpoint nie wpływa na wydajność — przerwanie następuje na poziomie procesora. Programowy (przy wyczerpaniu rejestrów sprzętowych) spowalnia wykonanie 10–50 razy, ponieważ LLDB sprawdza każdą instrukcję zapisu.

Podsumowanie

  • Watchpoint — punkt obserwacyjny zmiany pamięci, uruchamiany przy każdym zapisie pod wskazany adres z dowolnego wątku.
  • Sprzętowe watchpointy używają rejestrów DWT procesora i nie spowalniają wykonania, ale są ograniczone do 4–8 rejestrów.
  • LLDB obsługuje trzy typy watchpointów: na zmienną, na wyrażenie i na surowy adres pamięci.
  • Warunkowe watchpointy uruchamiają się tylko przy spełnieniu określonego wyrażenia — niezbędne do debugowania wysokoczęstotliwościowych zmian.
  • Watchpointy na właściwości obiektów i elementy kolekcji stają się nieaktualne przy ponownym przydzielaniu pamięci.
  • Watchpointy nie są przechowywane między sesjami i są usuwane przy wyjściu zmiennej z zakresu widoczności.
  • Watchpoint — najlepszy wybór, gdy znana jest zmienna, ale nieznane jest miejsce jej modyfikacji, szczególnie w kodzie wielowątkowym.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również