Rozszerzenia w Swift pojawiły się jako środek do rozszerzania typów — zarówno standardowych (np. String, Array), jak i własnych, bez potrzeby tworzenia dziedziczących klas czy zmiany oryginalnego kodu źródłowego. Umożliwia to dodawanie nowych metod, właściwości obliczalnych, realizacji protokołów, а nawet zgodności z protokołami, zachowując czytelność i jednolitą architekturę kodu.
Problem pojawia się przy nadmiernym lub chaotycznym używaniu rozszerzeń: łatwo stracić kontrolę nad pierwotnym zachowaniem typów, mogą wystąpić konflikty nazw i trudniej śledzić, skąd co pochodzi, szczególnie w dużych projektach lub przy podłączaniu zewnętrznych bibliotek.
Rozwiązanie polega na wyraźnej strukturze, organizacji rozszerzeń w grupy tematyczne, wyraźnej dokumentacji i unikaniu konfliktów z istniejącymi nazwami, a także w razie potrzeby ograniczeniu zakresu działania (np. przez fileprivate lub internal).
Przykład kodu:
extension String { var isEmail: Bool { return self.contains("@") && self.contains(".") } func trimmed() -> String { return trimmingCharacters(in: .whitespacesAndNewlines) } }
Kluczowe cechy:
Czy można dodać właściwość przechowywaną przez rozszerzenie?
Nie, rozszerzenie pozwala tylko na dodawanie właściwości obliczalnych i metod. Właściwości przechowywane (stored properties) nie mogą być dodawane przez rozszerzenie. Spróbuj — kompilator natychmiast zgłosi błąd.
Co się stanie, jeśli w dwóch różnych rozszerzeniach zadeklarujemy metody o tych samych nazwach dla jednego typu w różnych plikach?
Dojdzie do konfliktu nazw, a Swift nie będzie w stanie określić, którą metodę wywołać, a błąd ujawni się na etapie kompilacji.
Czy rozszerzenia mogą implementować metody prywatne, które są widoczne tylko wewnątrz rozszerzenia?
Tak, jeśli zadeklarujesz metodę jako prywatną, będzie ona widoczna tylko wewnątrz samego rozszerzenia i pliku, w którym została zadeklarowana (jeśli używany jest fileprivate).
extension Int { private func isEvenInternal() -> Bool { return self % 2 == 0 } func publicCheckEven() -> Bool { return isEvenInternal() } }
** Negatywny przypadek
W dużym projekcie dodaje się do String przez rozszerzenie metody do wszystkiego — od walidacji e-maili po parsowanie JSON. Po roku nikt nie może zrozumieć, skąd co pochodzi: metody pokrywają się nazwami, ktoś dodaje nową funkcję, nie wiedząc o starej, i psuje zachowanie zależności.
Zalety:
Wady:
** Pozytywny przypadek
Zespół używa rozszerzeń do grup logicznych: osobne rozszerzenie do walidacji, osobne — do formatowania, z prywatnymi pomocnikami wewnątrz. Wszystkie metody są udokumentowane, użycie nowych metod jest omawiane, istnieje przegląd kodu.
Zalety:
Wady: