willSet i didSet to obserwatory właściwości (property observers) w Swift, które pozwalają wykonać kod przed i po zmianie wartości właściwości. W przeciwieństwie do computed properties, obserwatory nie obliczają nowej wartości, a jedynie reagują na zmianę. Według dokumentacji Apple, The Swift Programming Language (2026), obserwatory są niezastąpione przy walidacji danych, synchronizacji interfejsu i logowaniu zmian w kodzie.
Najważniejsze
willSet i didSet to property observers (obserwatory właściwości) w Swift, wbudowany mechanizm śledzenia zmian stored properties.
W przeciwieństwie do innych języków, gdzie wymagana jest ręczna implementacja setterów lub systemów callback, Swift zapewnia deklaratywną składnię do reagowania na zmiany. Obserwatory dodawane są bezpośrednio po deklaracji właściwości i nie wymagają osobnego wywołania.
Według Apple Developer Documentation (2026), property observers są obsługiwane dla stored properties dowolnej klasy, struktury lub wyliczenia. Nie działają z computed properties, ponieważ te nie przechowują wartości — dla nich reakcja na zmianę jest implementowana bezpośrednio w setterze.
willSet wywoływany jest tuż przed przypisaniem nowej wartości do właściwości. Wewnątrz willSet dostępny jest niejawny parametr newValue, zawierający wartość, która zostanie ustawiona. W tym momencie bieżąca wartość właściwości jeszcze się nie zmieniła — możesz odczytać starą wartość bezpośrednio przez właściwość.
Według Swift Evolution proposal SE-0001 (2024), willSet umożliwia przeprowadzenie walidacji lub logowania przed faktyczną zmianą. Jeśli w willSet zostanie zgłoszony wyjątek — nowa wartość nie zostanie zastosowana, co czyni obserwatory mechanizmem ochrony danych.
didSet wywoływany jest tuż po przypisaniu nowej wartości. Wewnątrz didSet dostępny jest niejawny parametr oldValue, zawierający wartość sprzed zmiany. W tym momencie właściwość zawiera już nową wartość i możesz porównać ją ze starą.
Według Swift by Sundell (2025), didSet jest najpopularniejszym obserwatorem, ponieważ najczęściej potrzebny jest do post-processingu: aktualizacji UI, przeliczania zależnych pól lub wysyłania danych na serwer po zmianie.
Property observers deklaruje się bezpośrednio po właściwości, używając nawiasów klamrowych. Minimalna składnia wymaga tylko jednego obserwatora, ale można zadeklarować oba.
var score: Int = 0 {
willSet {
print("Wynik zmieni się na \(newValue)")
}
didSet {
print("Wynik zmienił się z \(oldValue) na \(score)")
}
}
Oba obserwatory są opcjonalne — można określić tylko willSet lub tylko didSet. Dla willSet można zmienić nazwę newValue, podając nazwę w nawiasach.
var username: String = "guest" {
willSet(newName) {
print("Zaraz ustawi \(newName)")
}
didSet(oldName) {
print("Było \(oldName), teraz \(username)")
}
}
Według Swift Language Guide (2026), zmiana nazw parametrów poprawia czytelność kodu, szczególnie gdy właściwość i obserwatory są używane w dużym projekcie z długimi nazwami.
Kolejność wykonania jest ściśle określona: najpierw willSet (stara wartość jest dostępna), następnie przypisanie, potem didSet (nowa wartość jest dostępna).
class Temperature {
var celsius: Double = 0.0 {
willSet {
print("Temperatura zmieni się z \(celsius) na \(newValue)")
}
didSet {
if celsius > 100.0 {
print("Przekroczono punkt wrzenia!")
}
}
}
}
Ważne ograniczenie: obserwatory nie są wywoływane przy inicjalizacji właściwości podczas tworzenia instancji. Wewnątrz init przypisanie wartości nie wyzwala willSet i didSet — zapobiega to niepożądanym efektom ubocznym na etapie konstrukcji.
Według Apple Swift Blog (2025), to zachowanie różni się od wielu innych języków, w których settery są wywoływane nawet w konstruktorach. Swift stawia na bezpieczeństwo: obserwatory zaczynają działać dopiero po zakończeniu inicjalizacji obiektu.
Zmiana właściwości wewnątrz didSet może prowadzić do ponownego wywołania obserwatorów. Swift nie blokuje rekurencji — programista musi kontrolować ją samodzielnie.
var counter: Int = 0 {
didSet {
if counter < 5 {
counter += 1
}
}
}
Taki kod stworzy całkowitą rekurencję z przepełnieniem stosu, jeśli nie przewidziano warunku wyjścia. Według Stack Overflow Swift Community (2025), jest to jeden z najczęstszych błędów początkujących programistów podczas pracy z property observers.
Struktury obsługują willSet i didSet dla stored properties bez ograniczeń. Należy pamiętać, że struktury są typami wartościowymi (value types), a modyfikacja właściwości wewnątrz mutującej metody również wyzwala obserwatory.
struct Point {
var x: Double = 0.0 {
didSet {
print("X zmieniło się na \(x)")
}
}
var y: Double = 0.0 {
didSet {
print("Y zmieniło się na \(y)")
}
}
}
var point = Point()
point.x = 5.0
Obserwatory właściwości są używane w projektach Swift do szerokiego spektrum zadań: od synchronizacji UI po walidację danych i logowanie.
didSet pozwala wycofać lub skorygować nieprawidłową wartość zaraz po jej ustawieniu. Zastępuje to rozwlekłe settery w Objective-C i zapewnia integralność danych na poziomie modelu.
var age: Int = 0 {
didSet {
if age < 0 || age > 150 {
age = oldValue
}
}
}
Przy zmianie powiązanej właściwości można automatycznie aktualizować elementy interfejsu bez osobnego wywoływania metody aktualizacji.
var userName: String = "" {
didSet {
nameLabel.text = userName
}
}
willSet jest wygodny do logowania w celach debugowania lub audytu. Możesz zapisać czas i nową wartość przed jej zastosowaniem, gwarantując, że log zawiera oryginalne dane do analizy.
Według objc.io (2025), property observers są szczególnie przydatne w architekturach z jednokierunkowym przepływem danych, gdzie każda zmiana właściwości jest rejestrowana do późniejszego odtworzenia stanu.
Computed properties obliczają wartość na bieżąco i nie mają magazynu, podczas gdy willSet i didSet działają na stored property z rzeczywistą wartością.
| Cecha | Property Observers | Computed Properties |
|---|---|---|
| Przechowują wartość | Tak | Nie |
| Wykonują kod przy zmianie | Tak | Nie |
| Typ deklaracji | var | var (get/set) |
| Parametry dostępu | newValue, oldValue | newValue (w set) |
| Inicjalizacja | Wymaga wartości początkowej | Nie wymaga |
Kluczowa różnica: computed property oblicza wartość przy każdym odczycie, a property observer reaguje na zmianę istniejącej wartości. Wybór między nimi jest podyktowany semantyką — jeśli właściwość jest pochodną innych danych, użyj computed; jeśli to samodzielna wartość, której zmiany należy obserwować, użyj willSet/didSet.
Najczęstszym błędem jest rekurencyjne wywołanie didSet bez warunku wyjścia. Każda zmiana właściwości wewnątrz didSet wyzwala observer ponownie, co prowadzi do nieskończonej pętli.
Drugim częstym błędem jest próba użycia obserwatorów na właściwościach let. Kompilator Swift zgłosi błąd, ponieważ let jest stałą.
Trzecim błędem jest ignorowanie faktu, że observer nie jest wywoływany przy inicjalizacji. Programiści oczekujący wywołania willSet wewnątrz init otrzymują nieoczekiwane zachowanie.
Czwartym problemem jest stosowanie obserwatorów do właściwości w extension. Swift zabrania dodawania willSet/didSet do stored properties w extension.
Według Ray Wenderlich (2025), zrozumienie tych ograniczeń pomaga uniknąć błędów na wczesnych etapach i czyni kod w Swift bardziej przewidywalnym.
Często zadawane pytania
Tak, każdy obserwator jest opcjonalny. Możesz zadeklarować tylko willSet, tylko didSet lub oba naraz.
Nie, Swift zabrania dodawania willSet i didSet w extension dla stored properties. Obserwatory deklaruje się tylko w oryginalnej definicji typu.
Nie, przy inicjalizacji obserwatory nie są wywoływane. To mechanizm ochronny zapobiegający efektom ubocznym na etapie konstrukcji obiektu.
willSet to obserwator stored property wykonywany przed zmianą wartości. Setter w computed property to sposób obliczania nowej wartości, a nie obserwowania istniejącej.
Ponowne wywołanie didSet spowoduje rekurencję. Bez warunku wyjścia doprowadzi to do przepełnienia stosu i awaryjnego zakończenia programu.
Podsumowanie
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.
Przeczytaj również