programowanieProgramista iOS

Jak w Swift zrealizować bezpieczną interakcję z danymi zmiennymi? Opisz podejścia i problemy, które mogą wystąpić w przypadku niewłaściwej implementacji.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

W Swift, aby zapewnić bezpieczeństwo wątków, często używa się GCD (Grand Central Dispatch) oraz kolejek (DispatchQueue), NSLock, a także nowoczesnych mechanizmów, takich jak actor (od Swift 5.5).

Podstawowa idea – dostęp do zmiennych danych odbywa się wyłącznie przez kolejki sekwencyjne lub przy użyciu synchronizatorów (blokad).

Przykład z GCD:

class ThreadSafeArray<Element> { private var array: [Element] = [] private let queue = DispatchQueue(label: "com.example.arrayQueue", attributes: .concurrent) func append(_ item: Element) { queue.async(flags: .barrier) { self.array.append(item) } } func get(index: Int) -> Element? { var result: Element? queue.sync { result = self.array.indices.contains(index) ? self.array[index] : nil } return result } }

Nowoczesne podejście: Aktorzy (Swift 5.5+):

actor SafeCounter { private var value = 0 func increment() { value += 1 } func get() -> Int { return value } }

Oba podejścia pozwalają uniknąć wyścigów danych i utrzymać spójność stanu.

Pytanie podchwytliwe

Pytanie:

Co się stanie, jeśli użyjesz DispatchQueue.sync wewnątrz Głównej Kolejki i dlaczego?

Odpowiedź: Wystąpi zakleszczenie (Deadlock), ponieważ Główna Kolejka już wykonuje zadanie i czeka na zakończenie operacji synchronizacyjnej w tej samej kolejce. W związku z tym, kolejka nie będzie mogła przetworzyć następnego zadania, dopóki bieżące nie zostanie zakończone, a to nigdy się nie zdarzy.

Przykład:

DispatchQueue.main.sync { // Zakleszczenie: ten wiersz nigdy się nie wykona }

Przykłady rzeczywistych błędów z powodu braku wiedzy na temat niuansów tematu


Historia

W projekcie używana była zmienna kolekcja, do której jednocześnie odnosiły się różne wątki bez synchronizacji. To prowadziło do awarii aplikacji i trudnych do uchwycenia błędów z powodu wyścigu danych: okresowo gubione były elementy, czasami występowały przekroczenia granic tablicy.


Historia

Programista niewłaściwie użył DispatchQueue.sync na głównej kolejce w czasie wykonywania, co spowodowało zakleszczenie i całkowite zatrzymanie UI użytkowników po wydaniu aktualizacji. Wymagano pilnego fixu i wycofania wydania.


Historia

Przy próbie uczynienia klasy bezpieczną dla wątków za pomocą NSLock, zapomniano wdrożyć blokadę/odblokadę dla wszystkich ścieżek wyjścia z metody (na przykład w przypadku błędu lub return wewnątrz guard), co prowadziło do potencjalnych zakleszczeń i poważnych problemów z wydajnością aplikacji.