Właściwości z obserwatorami (property observers) w Swift pozwalają reagować na zmiany wartości właściwości. Ta koncepcja pojawiła się razem z Swift dla zwiększenia przejrzystości kontroli nad zmianami danych i automatyzacji logiki podczas zmian.
Historia pytania:
Przed Swift podobne zachowanie często było realizowane ręcznie przez setter'y lub specjalne metody. W Swift obserwatory pojawiły się jako standardowe narzędzie w języku.
Problem:
Programista musi być w stanie przechwycić moment zmiany właściwości — na przykład, aby zaktualizować UI lub zwalidować dane. Bez obserwatorów kod stawałby się bardziej rozbudowany i mniej czytelny.
Rozwiązanie:
W Swift dostępne są dwa podstawowe obserwatory:
willSet jest wywoływany przed zmianą wartoścididSet jest wywoływany po przypisaniu nowej wartościObserwatory można dodać do przechowywanych właściwości, z wyjątkiem właściwości leniwych i obliczanych (computed) właściwości.
Przykład kodu:
class Temperature { var celsius: Double { willSet { print("Wkrótce ustawi się wartość", newValue) } didSet { print("Wartość była:", oldValue, ", a stała się:", celsius) } } init(celsius: Double) { self.celsius = celsius } } let temp = Temperature(celsius: 22) temp.celsius = 28 // Wywoła willSet i didSet
Kluczowe cechy:
Czy można dodać obserwatory do obliczanych (computed) właściwości?
Nie, do obliczanych właściwości nie można dodać willSet i didSet, ponieważ mają już własne gettery i settery. Użycie willSet/didSet jest aktualne tylko dla przechowywanych właściwości.
Czy obserwatory zostaną wywołane podczas zmiany właściwości wewnątrz inicjalizatora?
Nie, obserwatory właściwości nie są wywoływane podczas inicjalizacji (init). Działają tylko przy zmianie wartości po zakończeniu init.
Co się stanie, gdy przypiszesz bieżącą wartość samej sobie, na przykład x = x?
Obserwatory i tak zostaną wywołane, nawet jeśli wartość właściwości się nie zmieniła! Może to prowadzić do ubocznego wykonania logiki — bądź ostrożny.
var value: Int = 0 { didSet { print("didSet zawsze się wywołuje!") } } value = value // didSet się wywoła
Programista zaimplementował w didSet aktualizację interfejsu, ale nie kontrolował zmiany wartości. UI był aktualizowany nawet przy "pustym" przypisaniu, co obniżyło wydajność.
Zalety:
Wady:
W didSet sprawdzano równość starej i nowej wartości. Aktualizacja interfejsu następowała tylko wtedy, gdy wartość naprawdę się zmieniła.
Zalety:
Wady: