programowaniedeweloper iOS/Swift

Co to jest instrukcja defer w Swift? Jakie są cechy jej wykonania, gdzie jest sens ją stosować i z jakimi pułapkami można się spotkać?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Historia pytania:

Defer został dodany do Swift (inspirowany odpowiednikami w Go, C#) w celu gwarantowanego czyszczenia zasobów, nawet w przypadku wystąpienia błędów, wyjścia z funkcji lub zwracania wartości z różnych punktów funkcji.

Problem:

Przedwczesne zwalnianie, zapomniane czyszczenia zasobów (np. zamykanie plików, logowanie, rollback transakcji). Czasami myli się kolejność wykonania, błędnie zakładając, że defer wykonuje się w momencie deklaracji.

Rozwiązanie:

Defer to specjalny blok, który opóźnia wykonanie kodu do końca bieżącego zakresu (scope), zazwyczaj funkcji. Wszystkie defer są wykonywane w odwrotnej kolejności do umiejscowienia (LIFO). Pozwala to na centralne zarządzanie czyszczeniem zasobów, zwalnianiem pamięci lub rollbackiem transakcji.

Przykład kodu:

func processFile() { let file = File("/tmp/data.txt") file.open() defer { file.close() print("Plik zamknięty") } // Praca z plikiem print("Odczytywanie danych…") }

Kluczowe cechy:

  • Wykonuje się zawsze przy każdym wyjściu z zakresu, nawet w przypadku błędów i wcześniejszego returnu.
  • Kilka defer wykonuje się w odwrotnej kolejności.
  • Może być stosowany w dowolnym zakresie, nie tylko w funkcjach.

Pytania z haczykiem.

Czy kod wewnątrz defer wykonuje się w przypadku awarii aplikacji (crash) przed wyjściem z funkcji?

Nie, kod defer wykonuje się tylko przy poprawnym wyjściu z zakresu (scope). Jeśli aplikacja zakończyła działanie awaryjnie (na przykład, fatal error), defer się nie wykona.

Czy można używać return wewnątrz defer?

Nie, nie można. Blok defer nie pozwala na zwracanie wartości ani zakończenie zakresu, tylko instrukcje.

Czy defer może być używany do modyfikacji zmiennych zadeklarowanych przed defer?

Tak, defer przechwytuje wartości z bieżącego stosu w momencie wykonania. Można zmieniać wartości zadeklarowane przed defer, a one zachowają się przy wyjściu z zakresu.

Przykład kodu:

func example() -> Int { var result = 0 defer { result = 42 } return result // defer się wykona, wynik — 42 }

Typowe błędy i antywzorce

  • Błędne oczekiwanie wykonania defer od razu po deklaracji.
  • Zastosowanie defer poza zakresem, gdzie to nie ma sensu.
  • Pozostawienie ciężkich operacji wewnątrz defer.

Przykład z życia

Negatywny przypadek

Plik jest otwierany, ale zamykany tylko jawnie na końcu funkcji, a w przypadku błędów lub wcześniejszego wyjścia z funkcji plik pozostaje otwarty.

Zalety:

  • Prosta realizacja

Wady:

  • Nie zamyka pliku przy błędach
  • Wycieki zasobów

Pozytywny przypadek

Użycie defer do zamknięcia pliku od razu po otwarciu. Nawet jeśli wystąpi wyjątek lub zwrot z funkcji, plik zostanie gwarantowanie zamknięty.

Zalety:

  • Bezpiecznie, brak wycieków
  • Czysty i przewidywalny kod

Wady:

  • Należy zachować ostrożność z modyfikowalnymi zasobami wewnątrz defer