programowanieProgramista iOS

Jakie są kluczowe różnice między właściwościami lazy w Swift? Kiedy warto używać lazy, jakie są cechy i pułapki związane z ich inicjalizacją i jak uniknąć typowych problemów?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Właściwości lazy w Swift są obliczane tylko przy pierwszym odniesieniu do nich. Często stosuje się je dla obiektów, które są drogie pod względem zasobów (np. ciężkie obliczenia, pobieranie z sieci), które nie są potrzebne od razu. Deklaruje się je za pomocą słowa kluczowego lazy:

class DataFetcher { lazy var data: Data = self.loadData() func loadData() -> Data { /* … */ } }

Cechy i szczegóły:

  • Właściwości lazy mogą być stosowane tylko do zmiennych (var), nie do stałych (let).
  • W strukturach właściwości lazy nie działają, jeśli sama struktura jest immutable.
  • Jeżeli ustawia się przez inny wątek — nie jest to bezpieczne wątkowo. Należy unikać jednoczesnego dostępu do właściwości lazy z różnych wątków.
  • Przy kopiowaniu obiektu klasy wartość lazy jest cachowana dla każdego egzemplarza z osobna.

Pytanie z haczykiem.

Pytanie: "Czy wartość właściwości lazy jest tworzona podczas inicjalizacji egzemplarza klasy?"

Odpowiedź: Nie, wartość jest obliczana tylko przy pierwszym dostępie do właściwości, a nie podczas inicjalizacji.

class Expensive { init() { print("init") } } class Example { lazy var heavy = Expensive() } let foo = Example() // nic nie wypisuje _ = foo.heavy // teraz "init"

Przykłady rzeczywistych błędów z powodu nieznajomości szczegółów tematu.


Historia

W projekcie na dwie platformy używano leniwego tablicy (lazy var) do przechowywania cache’u obrazów. Przy jednoczesnym dostępie z kilku wątków występowały wyścigi, owinęli lazy var mutexami — ale zapomnieli o lazy, co doprowadziło do awarii aplikacji.


Historia

Młodszy programista próbował zadeklarować lazy let, aby zcache’ować ciężkie obliczenie. Kod nie kompilował się, ponieważ lazy jest dozwolone tylko dla var: trzeba było przemyśleć architekturę.


Historia

Programista deklarował właściwość lazy z przechwyceniem self wewnątrz closure podczas inicjalizacji. Doprowadziło to do cyklicznego odwołania — obiekt nie został zdeinicjalizowany nawet po odejściu ze wszystkich ekranów.